From be6341e6f014b47b5640a9b9b369832b849b06e2 Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Sat, 7 May 2016 15:15:51 -0400 Subject: [PATCH] create eplus (existing path, least used space) policy. closes #273 --- README.md | 1 + src/policy.cpp | 2 + src/policy.hpp | 3 + src/policy_eplus.cpp | 146 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 src/policy_eplus.cpp diff --git a/README.md b/README.md index 5a17351d..32ffbee1 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ Due to FUSE limitations **ioctl** behaves differently if its acting on a directo |--------------|-------------| | all | Search category: acts like **ff**. Action category: apply to all found. Create category: for **mkdir**, **mknod**, and **symlink** it will apply to all found. **create** works like **ff**. It will exclude readonly drives and those with free space less than **minfreespace**. | | eplfs (existing path, least free space) | If the path exists on multiple drives use the one with the least free space. For **create** category it will exclude readonly drives and those with free space less than **minfreespace**. Falls back to **lfs**. | +| eplus (existing path, least used space) | If the path exists on multiple drives the the one with the least used space. For **create** category it will exclude readonly drives and those with free space less than **minfreespace**. Falls back to **lus**. | | epmfs (existing path, most free space) | If the path exists on multiple drives use the one with the most free space. For **create** category it will exclude readonly drives and those with free space less than **minfreespace**. Falls back to **mfs**. | | erofs | Exclusively return **-1** with **errno** set to **EROFS**. By setting **create** functions to this you can in effect turn the filesystem readonly. | | ff (first found) | Given the order of the drives, as defined at mount time or when configured via xattr interface, act on the first one found. For **create** category it will exclude readonly drives and those with free space less than **minfreespace** (unless there is no other option). | diff --git a/src/policy.cpp b/src/policy.cpp index e83f79b7..f8d40f22 100644 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -31,6 +31,7 @@ namespace mergerfs (POLICY(invalid,DOESNT_PRESERVE_PATH)) (POLICY(all,DOESNT_PRESERVE_PATH)) (POLICY(eplfs,PRESERVES_PATH)) + (POLICY(eplus,PRESERVES_PATH)) (POLICY(epmfs,PRESERVES_PATH)) (POLICY(erofs,DOESNT_PRESERVE_PATH)) (POLICY(ff,DOESNT_PRESERVE_PATH)) @@ -47,6 +48,7 @@ namespace mergerfs CONST_POLICY(invalid); CONST_POLICY(all); CONST_POLICY(eplfs); + CONST_POLICY(eplus); CONST_POLICY(epmfs); CONST_POLICY(erofs); CONST_POLICY(ff); diff --git a/src/policy.hpp b/src/policy.hpp index 3807428b..d825c7f6 100644 --- a/src/policy.hpp +++ b/src/policy.hpp @@ -44,6 +44,7 @@ namespace mergerfs BEGIN = 0, all = BEGIN, eplfs, + eplus, epmfs, erofs, ff, @@ -97,6 +98,7 @@ namespace mergerfs static int invalid(CType,cstrvec&,const char *,csize_t,cstrptrvec&); static int all(CType,cstrvec&,const char*,csize_t,cstrptrvec&); static int eplfs(CType,cstrvec&,const char *,csize_t,cstrptrvec&); + static int eplus(CType,cstrvec&,const char *,csize_t,cstrptrvec&); static int epmfs(CType,cstrvec&,const char *,csize_t,cstrptrvec&); static int erofs(CType,cstrvec&,const char *,csize_t,cstrptrvec&); static int ff(CType,cstrvec&,const char *,csize_t,cstrptrvec&); @@ -169,6 +171,7 @@ namespace mergerfs static const Policy &invalid; static const Policy &all; static const Policy &eplfs; + static const Policy ⩱ static const Policy &epmfs; static const Policy &erofs; static const Policy &ff; diff --git a/src/policy_eplus.cpp b/src/policy_eplus.cpp new file mode 100644 index 00000000..ebfe9ffa --- /dev/null +++ b/src/policy_eplus.cpp @@ -0,0 +1,146 @@ +/* + Copyright (c) 2016, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include + +#include +#include +#include + +#include "fs.hpp" +#include "fs_path.hpp" +#include "policy.hpp" + +using std::string; +using std::vector; +using std::size_t; +using mergerfs::Category; + +static +int +_eplus_create(const vector &basepaths, + const char *fusepath, + const size_t minfreespace, + vector &paths) +{ + string fullpath; + size_t eplus; + const string *eplusbasepath; + + eplus = std::numeric_limits::max(); + eplusbasepath = NULL; + for(size_t i = 0, ei = basepaths.size(); i != ei; i++) + { + bool readonly; + size_t spaceavail; + size_t spaceused; + const string *basepath = &basepaths[i]; + + fs::path::make(basepath,fusepath,fullpath); + + if(!fs::exists(fullpath)) + continue; + if(!fs::info(*basepath,readonly,spaceavail,spaceused)) + continue; + if(readonly) + continue; + if(spaceavail < minfreespace) + continue; + if(spaceused >= eplus) + continue; + + eplus = spaceused; + eplusbasepath = basepath; + } + + if(eplusbasepath == NULL) + return POLICY_FAIL_ENOENT; + + paths.push_back(eplusbasepath); + + return POLICY_SUCCESS; +} + +static +int +_eplus_other(const vector &basepaths, + const char *fusepath, + vector &paths) +{ + string fullpath; + size_t eplus; + const string *eplusbasepath; + + eplus = 0; + eplusbasepath = NULL; + for(size_t i = 0, ei = basepaths.size(); i != ei; i++) + { + size_t spaceused; + const string *basepath = &basepaths[i]; + + fs::path::make(basepath,fusepath,fullpath); + + if(!fs::exists(fullpath)) + continue; + if(!fs::spaceused(*basepath,spaceused)) + continue; + if(spaceused >= eplus) + continue; + + eplus = spaceused; + eplusbasepath = basepath; + } + + if(eplusbasepath == NULL) + return POLICY_FAIL_ENOENT; + + paths.push_back(eplusbasepath); + + return POLICY_SUCCESS; +} + +static +int +_eplus(const Category::Enum::Type type, + const vector &basepaths, + const char *fusepath, + const size_t minfreespace, + vector &paths) +{ + if(type == Category::Enum::create) + return _eplus_create(basepaths,fusepath,minfreespace,paths); + + return _eplus_other(basepaths,fusepath,paths); +} + +namespace mergerfs +{ + int + Policy::Func::eplus(const Category::Enum::Type type, + const vector &basepaths, + const char *fusepath, + const size_t minfreespace, + vector &paths) + { + int rv; + + rv = _eplus(type,basepaths,fusepath,minfreespace,paths); + if(POLICY_FAILED(rv)) + rv = Policy::Func::lus(type,basepaths,fusepath,minfreespace,paths); + + return rv; + } +}