Browse Source

Add LUP policy (#1601)

pull/1603/head
François-Xavier Payet 3 weeks ago
committed by GitHub
parent
commit
22df87c86a
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      mkdocs/docs/config/functions_categories_policies.md
  2. 4
      src/policies.cpp
  3. 4
      src/policies.hpp
  4. 240
      src/policy_lup.cpp
  5. 67
      src/policy_lup.hpp

1
mkdocs/docs/config/functions_categories_policies.md

@ -116,6 +116,7 @@ but it makes things a bit more uniform.
| mfs (most free space) | Pick the branch with the most available free space. |
| ff (first found) | Given the order of the branches, as defined at mount time or configured at runtime, act on the first one found. |
| lfs (least free space) | Pick the branch with the least available free space. |
| lup (least used percent) | Pick the branch with the least used percentage of space |
| lus (least used space) | Pick the branch with the least used space. |
| all | Search: For **mkdir**, **mknod**, and **symlink** it will apply to all branches. **create** works like **ff**. |
| msppfrd (most shared path, percentage free random distribution) | Like **eppfrd** but if it fails to find a branch it will try again with the parent directory. Continues this pattern till finding one. |

4
src/policies.cpp

@ -35,6 +35,7 @@
FUNC(ff) \
FUNC(lfs) \
FUNC(lus) \
FUNC(lup) \
FUNC(mfs) \
FUNC(msplfs) \
FUNC(msplus) \
@ -80,6 +81,7 @@ Policy::ERoFS::Action Policies::Action::erofs;
Policy::FF::Action Policies::Action::ff;
Policy::LFS::Action Policies::Action::lfs;
Policy::LUS::Action Policies::Action::lus;
Policy::LUP::Action Policies::Action::lup;
Policy::MFS::Action Policies::Action::mfs;
Policy::MSPLFS::Action Policies::Action::msplfs;
Policy::MSPLUS::Action Policies::Action::msplus;
@ -101,6 +103,7 @@ Policy::ERoFS::Create Policies::Create::erofs;
Policy::FF::Create Policies::Create::ff;
Policy::LFS::Create Policies::Create::lfs;
Policy::LUS::Create Policies::Create::lus;
Policy::LUP::Create Policies::Create::lup;
Policy::MFS::Create Policies::Create::mfs;
Policy::MSPLFS::Create Policies::Create::msplfs;
Policy::MSPLUS::Create Policies::Create::msplus;
@ -122,6 +125,7 @@ Policy::ERoFS::Search Policies::Search::erofs;
Policy::FF::Search Policies::Search::ff;
Policy::LFS::Search Policies::Search::lfs;
Policy::LUS::Search Policies::Search::lus;
Policy::LUP::Search Policies::Search::lup;
Policy::MFS::Search Policies::Search::mfs;
Policy::MSPLFS::Search Policies::Search::msplfs;
Policy::MSPLUS::Search Policies::Search::msplus;

4
src/policies.hpp

@ -30,6 +30,7 @@
#include "policy_ff.hpp"
#include "policy_lfs.hpp"
#include "policy_lus.hpp"
#include "policy_lup.hpp"
#include "policy_mfs.hpp"
#include "policy_msplfs.hpp"
#include "policy_msplus.hpp"
@ -56,6 +57,7 @@ struct Policies
static Policy::ERoFS::Action erofs;
static Policy::FF::Action ff;
static Policy::LFS::Action lfs;
static Policy::LUP::Action lup;
static Policy::LUS::Action lus;
static Policy::MFS::Action mfs;
static Policy::MSPLFS::Action msplfs;
@ -82,6 +84,7 @@ struct Policies
static Policy::ERoFS::Create erofs;
static Policy::FF::Create ff;
static Policy::LFS::Create lfs;
static Policy::LUP::Create lup;
static Policy::LUS::Create lus;
static Policy::MFS::Create mfs;
static Policy::MSPLFS::Create msplfs;
@ -108,6 +111,7 @@ struct Policies
static Policy::ERoFS::Search erofs;
static Policy::FF::Search ff;
static Policy::LFS::Search lfs;
static Policy::LUP::Search lup;
static Policy::LUS::Search lus;
static Policy::MFS::Search mfs;
static Policy::MSPLFS::Search msplfs;

240
src/policy_lup.cpp

@ -0,0 +1,240 @@
/*
Copyright (c) 2025, Antonio SJ Musumeci <trapexit@spawn.link> and contributors
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 "policy_lup.hpp"
#include "errno.hpp"
#include "fs_exists.hpp"
#include "fs_info.hpp"
#include "fs_path.hpp"
#include "policies.hpp"
#include "fs_statvfs_cache.hpp"
#include "policy.hpp"
#include "policy_error.hpp"
#include "rwlock.hpp"
#include <limits>
#include <string>
using std::string;
static
int
_action(const Branches::Ptr &branches_,
const fs::path &fusepath_,
std::vector<Branch *> &paths_)
{
int rv;
int error;
fs::info_t info;
Branch *obranch;
obranch = nullptr;
error = ENOENT;
uint64_t best_used = 0;
uint64_t best_total = 1;
for (auto &branch : *branches_)
{
if (branch.ro())
error_and_continue(error, EROFS);
if (!fs::exists(branch.path, fusepath_))
error_and_continue(error, ENOENT);
rv = fs::info(branch.path, &info);
if (rv < 0)
error_and_continue(error, ENOENT);
if (info.readonly)
error_and_continue(error, EROFS);
uint64_t used = info.spaceused;
uint64_t total = info.spaceused + info.spaceavail;
if (total == 0)
{
used = 0;
total = 1;
}
if (obranch == nullptr)
{
best_used = used;
best_total = total;
obranch = &branch;
continue;
}
unsigned __int128 lhs = (unsigned __int128)used * (unsigned __int128)best_total;
unsigned __int128 rhs = (unsigned __int128)best_used * (unsigned __int128)total;
if (lhs >= rhs)
continue;
best_used = used;
best_total = total;
obranch = &branch;
}
if (obranch == nullptr)
return -error;
paths_.push_back(obranch);
return 0;
}
static
int
_search(const Branches::Ptr &branches_,
const fs::path &fusepath_,
std::vector<Branch *> &paths_)
{
int rv;
uint64_t used;
uint64_t avail;
uint64_t best_used = 0;
uint64_t best_total = 1;
Branch *obranch;
obranch = nullptr;
for (auto &branch : *branches_)
{
if (!fs::exists(branch.path, fusepath_))
continue;
rv = fs::statvfs_cache_spaceused(branch.path, &used);
if (rv < 0)
continue;
rv = fs::statvfs_cache_spaceavail(branch.path, &avail);
if (rv < 0)
continue;
uint64_t total = used + avail;
if (total == 0)
{
used = 0;
total = 1;
}
if (obranch == nullptr)
{
best_used = used;
best_total = total;
obranch = &branch;
continue;
}
unsigned __int128 lhs = (unsigned __int128)used * (unsigned __int128)best_total;
unsigned __int128 rhs = (unsigned __int128)best_used * (unsigned __int128)total;
if (lhs >= rhs)
continue;
best_used = used;
best_total = total;
obranch = &branch;
}
if (obranch == nullptr)
return -ENOENT;
paths_.push_back(obranch);
return 0;
}
static
int
_create(const Branches::Ptr &branches_,
std::vector<Branch *> &paths_)
{
int rv;
int error;
fs::info_t info;
Branch *obranch;
obranch = nullptr;
error = ENOENT;
uint64_t best_used = 0;
uint64_t best_total = 1;
for (auto &branch : *branches_)
{
if (branch.ro_or_nc())
error_and_continue(error, EROFS);
rv = fs::info(branch.path, &info);
if (rv < 0)
error_and_continue(error, ENOENT);
if (info.readonly)
error_and_continue(error, EROFS);
if (info.spaceavail < branch.minfreespace())
error_and_continue(error, ENOSPC);
uint64_t used = info.spaceused;
uint64_t total = info.spaceused + info.spaceavail;
if (total == 0)
{
used = 0;
total = 1;
}
if (obranch == nullptr)
{
best_used = used;
best_total = total;
obranch = &branch;
continue;
}
unsigned __int128 lhs = (unsigned __int128)used * (unsigned __int128)best_total;
unsigned __int128 rhs = (unsigned __int128)best_used * (unsigned __int128)total;
if (lhs >= rhs)
continue;
best_used = used;
best_total = total;
obranch = &branch;
}
if (obranch == nullptr)
return -error;
paths_.push_back(obranch);
return 0;
}
int
Policy::LUP::Action::operator()(const Branches::Ptr &branches_,
const fs::path &fusepath_,
std::vector<Branch *> &paths_) const
{
return ::_action(branches_, fusepath_, paths_);
}
int
Policy::LUP::Create::operator()(const Branches::Ptr &branches_,
const fs::path &fusepath_,
std::vector<Branch *> &paths_) const
{
return ::_create(branches_, paths_);
}
int
Policy::LUP::Search::operator()(const Branches::Ptr &branches_,
const fs::path &fusepath_,
std::vector<Branch *> &paths_) const
{
return ::_search(branches_, fusepath_, paths_);
}

67
src/policy_lup.hpp

@ -0,0 +1,67 @@
/*
ISC License
Copyright (c) 2025, Antonio SJ Musumeci <trapexit@spawn.link> and contributors
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.
*/
#pragma once
#include "policy.hpp"
namespace Policy
{
namespace LUP
{
class Action final : public Policy::ActionImpl
{
public:
Action()
: Policy::ActionImpl("lup")
{}
public:
int operator()(const Branches::Ptr &,
const fs::path &,
std::vector<Branch *> &) const final;
};
class Create final : public Policy::CreateImpl
{
public:
Create()
: Policy::CreateImpl("lup")
{}
public:
int operator()(const Branches::Ptr &,
const fs::path &,
std::vector<Branch *> &) const final;
bool path_preserving() const final { return false; }
};
class Search final : public Policy::SearchImpl
{
public:
Search()
: Policy::SearchImpl("lup")
{}
public:
int operator()(const Branches::Ptr &,
const fs::path &,
std::vector<Branch *> &) const final;
};
}
}
Loading…
Cancel
Save