diff --git a/README.md b/README.md index 0711e949..7c8631ac 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Why create **mergerfs** when those exist? **mhddfs** has not been updated in som ###options### * **defaults** is a shortcut for **auto_cache**. **big_writes**, **atomic_o_trunc**, **splice_read**, **splice_write**, and **splice_move** are in effect also enabled (by asking **FUSE** internally for such features) but if unavailable will be ignored. These options seem to provide the best performance. -* **minfreespace** (defaults to **4G**) is the minimum space value used for the **lfs** and **fwfs** policies. Understands 'K', 'M', and 'G' to represent kilobyte, megabyte, and gigabyte respectively. +* **minfreespace** (defaults to **4G**) is the minimum space value used for the **lfs**, **fwfs**, and **epmfs** policies. Understands 'K', 'M', and 'G' to represent kilobyte, megabyte, and gigabyte respectively. * All FUSE functions which have a category (see below) are option keys. The syntax being **func.<func>=<policy>**. Example: **func.getattr=newest**. * To set all function policies in a category use **categor.<category>=<policy>**. Example: **category.create=mfs**. * Options are evaluated in the order listed so if the options are **func.rmdir=rand,category.action=ff** the **action** category setting will override the **rmdir** setting. @@ -64,14 +64,14 @@ Filesystem calls are broken up into 3 categories: **action**, **create**, **sear | Policy | Description | |--------------|-------------| -| ff (first found) | Given the order of the paths act on the first one found (regardless if stat would return EACCES). | -| ffwp (first found w/ permissions) | Given the order of the paths act on the first one found which you have access (stat does not error with EACCES). | +| ff (first found) | Given the order of the drives act on the first one found (regardless if stat would return EACCES). | +| ffwp (first found w/ permissions) | Given the order of the drives act on the first one found which you have access (stat does not error with EACCES). | | newest (newest file) | If multiple files exist return the one with the most recent mtime. | | mfs (most free space) | Use the drive with the most free space available. | -| epmfs (existing path, most free space) | If the path exists in multiple locations use the one with the most free space. Otherwise fall back to **mfs**. | -| fwfs (first with free space) | Pick the first path which has at least **minfreespace**. | -| lfs (least free space) | Pick the path with least available space but more than **minfreespace**. | -| rand (random) | Pick an existing destination at random. | +| epmfs (existing path, most free space) | If the path exists on multiple drives use the one with the most free space and is greater than **minfreespace**. If no drive has at least **minfreespace** then fallback to **mfs**. | +| fwfs (first with free space) | Pick the first drive which has at least **minfreespace**. | +| lfs (least free space) | Pick the drive with least available space but more than **minfreespace**. | +| rand (random) | Pick an existing drive at random. | | all | Applies action to all found. For searches it will behave like first found **ff**. | | enosys, einval, enotsup, exdev, erofs | Exclusively return `-1` with `errno` set to the respective value. Useful for debugging other applications' behavior to errors. | diff --git a/src/policy_epmfs.cpp b/src/policy_epmfs.cpp index d712b5d9..e158d13f 100644 --- a/src/policy_epmfs.cpp +++ b/src/policy_epmfs.cpp @@ -36,117 +36,57 @@ using std::string; using std::vector; using std::size_t; +using mergerfs::Policy; +using mergerfs::Category; +typedef struct statvfs statvfs_t; static inline void -_calc_epmfs(const struct statvfs &fsstats, - const string &basepath, - fsblkcnt_t &epmfs, - string &epmfsbasepath, - fsblkcnt_t &mfs, - string &mfsbasepath) +_calc_mfs(const statvfs_t &fsstats, + const string &basepath, + const size_t minfreespace, + fsblkcnt_t &mfs, + string &mfsbasepath) { fsblkcnt_t spaceavail; spaceavail = (fsstats.f_frsize * fsstats.f_bavail); - if(spaceavail > epmfs) - { - epmfs = spaceavail; - epmfsbasepath = basepath; - } - - if(spaceavail > mfs) + if((spaceavail > minfreespace) && (spaceavail > mfs)) { mfs = spaceavail; mfsbasepath = basepath; } } -static -inline -void -_calc_mfs(const struct statvfs &fsstats, - const string &basepath, - fsblkcnt_t &mfs, - string &mfsbasepath) -{ - fsblkcnt_t spaceavail; - - spaceavail = (fsstats.f_frsize * fsstats.f_bavail); - if(spaceavail > mfs) - { - mfs = spaceavail; - mfsbasepath = basepath; - } -} - -static -inline -int -_try_statvfs(const string &basepath, - const string &fullpath, - fsblkcnt_t &epmfs, - string &epmfsbasepath, - fsblkcnt_t &mfs, - string &mfsbasepath) -{ - int rv; - struct statvfs fsstats; - - rv = ::statvfs(fullpath.c_str(),&fsstats); - if(rv == 0) - _calc_epmfs(fsstats,basepath,epmfs,epmfsbasepath,mfs,mfsbasepath); - - return rv; -} - -static -inline -int -_try_statvfs(const string &basepath, - fsblkcnt_t &mfs, - string &mfsbasepath) -{ - int rv; - struct statvfs fsstats; - - rv = ::statvfs(basepath.c_str(),&fsstats); - if(rv == 0) - _calc_mfs(fsstats,basepath,mfs,mfsbasepath); - - return rv; -} - static int _epmfs_create(const vector &basepaths, const string &fusepath, + const size_t minfreespace, vector &paths) { + int rv; fsblkcnt_t epmfs; - fsblkcnt_t mfs; - string mfsbasepath; string epmfsbasepath; string fullpath; + statvfs_t fsstats; - mfs = 0; epmfs = 0; for(size_t i = 0, ei = basepaths.size(); i != ei; i++) { - int rv; const string &basepath = basepaths[i]; - fullpath = fs::path::make(basepath,fusepath); + fs::path::make(basepath,fusepath,fullpath); - rv = _try_statvfs(basepath,fullpath,epmfs,epmfsbasepath,mfs,mfsbasepath); - if(rv == -1) - _try_statvfs(basepath,mfs,mfsbasepath); + rv = ::statvfs(fullpath.c_str(),&fsstats); + if(rv == 0) + _calc_mfs(fsstats,basepath,minfreespace,epmfs,epmfsbasepath); } if(epmfsbasepath.empty()) - epmfsbasepath = mfsbasepath; + return Policy::Func::mfs(Category::Enum::create,basepaths,fusepath,minfreespace,paths); paths.push_back(epmfsbasepath); @@ -160,22 +100,22 @@ _epmfs(const vector &basepaths, vector &paths) { + int rv; fsblkcnt_t epmfs; string epmfsbasepath; string fullpath; + statvfs_t fsstats; epmfs = 0; for(size_t i = 0, ei = basepaths.size(); i != ei; i++) { - int rv; - struct statvfs fsstats; const string &basepath = basepaths[i]; - fullpath = fs::path::make(basepath,fusepath); + fs::path::make(basepath,fusepath,fullpath); rv = ::statvfs(fullpath.c_str(),&fsstats); if(rv == 0) - _calc_mfs(fsstats,basepath,epmfs,epmfsbasepath); + _calc_mfs(fsstats,basepath,0,epmfs,epmfsbasepath); } if(epmfsbasepath.empty()) @@ -196,7 +136,7 @@ namespace mergerfs vector &paths) { if(type == Category::Enum::create) - return _epmfs_create(basepaths,fusepath,paths); + return _epmfs_create(basepaths,fusepath,minfreespace,paths); return _epmfs(basepaths,fusepath,paths); }