commit:     084f76dbbc0c7b238375d094ced3f957941825d6
Author:     Michał Górny <mgorny <AT> gentoo <DOT> org>
AuthorDate: Tue Dec 30 19:57:53 2025 +0000
Commit:     Michał Górny <mgorny <AT> gentoo <DOT> org>
CommitDate: Tue Dec 30 19:57:53 2025 +0000
URL:        https://gitweb.gentoo.org/proj/steve.git/commit/?id=084f76db

Add sanity checks for --min-memory-avail

Signed-off-by: Michał Górny <mgorny <AT> gentoo.org>

 src/steve.cxx | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/src/steve.cxx b/src/steve.cxx
index 1751fe7..dd89412 100644
--- a/src/steve.cxx
+++ b/src/steve.cxx
@@ -121,6 +121,7 @@ struct steve_state {
        double load_avg{-1};
        int64_t min_memory_avail{-1}; /* <= 0 implies none */
        int64_t memory_avail{-1};
+       int64_t memory_total{-1};
        int64_t tokens;
        std::deque<steve_waiter> waiters;
        std::unordered_map<uint64_t, steve_process> processes;
@@ -199,7 +200,7 @@ static std::optional<long> steve_get_meminfo(int fd, 
std::string_view label)
        buf[rd + 1] = 0;
        char *match = strstr(buf, label.data());
        if (!match) {
-               std::print(stderr, "Parsing /proc/meminfo failed: no {}\n", 
label);
+               std::print(stderr, "Parsing /proc/meminfo failed: no {}\n", 
label.substr(1));
                return {};
        }
        match += label.size();
@@ -494,7 +495,8 @@ static void steve_init(void *userdata, struct 
fuse_conn_info *)
        if (state->max_load_avg > 0)
                std::print(stderr, "  tokens will be served with load average < 
{:.3}\n", state->max_load_avg);
        if (state->min_memory_avail > 0)
-               std::print(stderr, "  tokens will be served with memory 
available >= {} MiB\n", state->min_memory_avail);
+               std::print(stderr, "  tokens will be served with memory 
available >= {} MiB (out of {} MiB)\n",
+                       state->min_memory_avail, state->memory_total);
        if (state->max_load_avg > 0 || state->min_memory_avail > 0)
                std::print(stderr, "  with a recheck timeout of {} s {} us\n",
                                state->recheck_timeout.tv_sec, 
state->recheck_timeout.tv_usec);
@@ -899,6 +901,15 @@ static void steve_ioctl(
                        steve_wake_waiters(state);
                        break;
                case STEVE_IOC_SET_MIN_MEMORY_AVAIL:
+                       if (state->memory_total == -1) {
+                               auto memtotal = steve_get_meminfo(state, 
"\nMemTotal:");
+                               if (memtotal.has_value())
+                                       state->memory_total = memtotal.value() 
/ 1024;
+                       }
+                       if (val > state->memory_total) {
+                               fuse_reply_err(req, EINVAL);
+                               return;
+                       }
                        state->min_memory_avail = val;
                        std::print(stderr, "{} set min. available memory to {} 
MiB\n", steve_process_id(fi->fh, process), state->min_memory_avail);
                        fuse_reply_ioctl(req, 0, nullptr, 0);
@@ -1170,6 +1181,19 @@ int main(int argc, char **argv)
                                state.min_jobs, state.jobs);
                return 1;
        }
+       if (state.min_memory_avail != -1) {
+               auto memtotal = steve_get_meminfo(&state, "\nMemTotal:");
+               if (!memtotal.has_value()) {
+                       std::print(stderr, "--min-memory-avail specified but 
memory info not available\n");
+                       return 1;
+               }
+               state.memory_total = memtotal.value() / 1024;
+               if (state.memory_total < state.min_memory_avail) {
+                       std::print(stderr, "--min-memory-avail requests {} MiB 
available, but the system has only {} MiB memory\n",
+                                       state.min_memory_avail, 
state.memory_total);
+                       return 1;
+               }
+       }
 
        std::unique_ptr<struct event_base, std::function<void(struct 
event_base*)>>
                evb{event_base_new(), event_base_free};

Reply via email to