Cap the number of dumps

Calculate number of dumps allowed in a system based on
individual dump Max size configured in the system.

Algorithm: Setting Dump size to maximum size,
if (dump entries + active dumps) is less than total allowed dump entries.
Otherwise return error.

Next patch will provide additional algorithm to cap the
dump based on actual size of the dump files.

Change-Id: Id8916a31d72f5c2f2f23eaf68062b829b7e4100c
Signed-off-by: Jayanth Othayoth <ojayanth@in.ibm.com>
diff --git a/configure.ac b/configure.ac
index 7d93605..3a042cd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -63,5 +63,13 @@
 AS_IF([test "x$BMC_DUMP_PATH" == "x"], [BMC_DUMP_PATH="/tmp/dumps"])
 AC_DEFINE_UNQUOTED([BMC_DUMP_PATH], ["$BMC_DUMP_PATH"], [Directory where bmc dumps are placed])
 
+AC_ARG_VAR(BMC_DUMP_MAX_SIZE, [Maximum size of one bmc dump in kilo bytes])
+AS_IF([test x$BMC_DUMP_MAX_SIZE == x], [BMC_DUMP_MAX_SIZE=200])
+AC_DEFINE_UNQUOTED([BMC_DUMP_MAX_SIZE], [$BMC_DUMP_MAX_SIZE], [Maximum size of one bmc dump in kilo bytes])
+
+AC_ARG_VAR(BMC_DUMP_TOTAL_SIZE, [Total size of the bmc dump in kilo bytes])
+AS_IF([test x$BMC_DUMP_TOTAL_SIZE == x], [BMC_DUMP_TOTAL_SIZE=1024])
+AC_DEFINE_UNQUOTED([BMC_DUMP_TOTAL_SIZE], [$BMC_DUMP_TOTAL_SIZE], [Total size of the dump in kilo bytes])
+
 AC_CONFIG_FILES([Makefile])
 AC_OUTPUT
diff --git a/dump_manager.cpp b/dump_manager.cpp
index 02429c2..80e117b 100644
--- a/dump_manager.cpp
+++ b/dump_manager.cpp
@@ -2,11 +2,13 @@
 #include <sys/inotify.h>
 #include <regex>
 
+#include <phosphor-logging/elog.hpp>
 #include <phosphor-logging/elog-errors.hpp>
 
 #include "dump_manager.hpp"
 #include "dump_internal.hpp"
 #include "xyz/openbmc_project/Common/error.hpp"
+#include "xyz/openbmc_project/Dump/Create/error.hpp"
 #include "config.h"
 
 namespace phosphor
@@ -79,11 +81,17 @@
         elog<InternalFailure>();
     }
 
+    //Increment active dump count.
+    activeDumpCount++;
+
     return ++lastEntryId;
 }
 
 void Manager::createEntry(const fs::path& file)
 {
+    //Decrement the Dump in progress counter.
+    activeDumpCount = (activeDumpCount == 0 ? 0 : activeDumpCount - 1);
+
     //Dump File Name format obmcdump_ID_EPOCHTIME.EXT
     static constexpr auto ID_POS         = 1;
     static constexpr auto EPOCHTIME_POS  = 2;
@@ -147,17 +155,17 @@
         else if ((IN_CREATE == i.second) && fs::is_directory(i.first))
         {
             auto watchObj = std::make_unique<Watch>(
-                                    eventLoop,
-                                    IN_NONBLOCK,
-                                    IN_CLOSE_WRITE,
-                                    EPOLLIN,
-                                    i.first,
-                                    std::bind(
-                                         std::mem_fn(
-                                      &phosphor::dump::Manager::watchCallback),
-                                         this, std::placeholders::_1));
+                                eventLoop,
+                                IN_NONBLOCK,
+                                IN_CLOSE_WRITE,
+                                EPOLLIN,
+                                i.first,
+                                std::bind(
+                                    std::mem_fn(
+                                       &phosphor::dump::Manager::watchCallback),
+                                    this, std::placeholders::_1));
 
-           childWatchMap.emplace(i.first, std::move(watchObj));
+            childWatchMap.emplace(i.first, std::move(watchObj));
         }
 
     }
@@ -199,5 +207,31 @@
     }
 }
 
+size_t Manager::getAllowedSize()
+{
+    using namespace sdbusplus::xyz::openbmc_project::Dump::Create::Error;
+    using Reason = xyz::openbmc_project::Dump::Create::QuotaExceeded::REASON;
+
+    auto size = 0;
+
+    // Maximum number of dump is based on total dump size
+    // and individual dump Max size configured in the system.
+    // Set the new dump size to max, in case sum of available
+    // dump and active dumps is less than maximum number of dumps.
+
+    constexpr auto dumpCount = BMC_DUMP_TOTAL_SIZE / BMC_DUMP_MAX_SIZE;
+
+    if ((entries.size() + activeDumpCount) < dumpCount)
+    {
+        size = BMC_DUMP_MAX_SIZE;
+    }
+    else
+    {
+        //Reached to maximum limit
+        elog<QuotaExceeded>(Reason("Not enough space: Delete old dumps"));
+    }
+    return size;
+}
+
 } //namespace dump
 } //namespace phosphor
diff --git a/dump_manager.hpp b/dump_manager.hpp
index 8318f37..9856f1e 100644
--- a/dump_manager.hpp
+++ b/dump_manager.hpp
@@ -64,6 +64,7 @@
             bus(bus),
             eventLoop(event.get()),
             lastEntryId(0),
+            activeDumpCount(0),
             dumpWatch(eventLoop,
                   IN_NONBLOCK,
                   IN_CLOSE_WRITE | IN_CREATE,
@@ -136,6 +137,14 @@
           */
         void removeWatch(const fs::path& path);
 
+        /** @brief Calculate per dump allowed size based on number of
+          *        existing dumps and total dump size. Returns
+          *        allowed size for a dump in kilo bytes.
+          *  @returns 0 indicates no space is available in dump location
+          *           non zero value indicates size of one dump.
+          */
+        size_t getAllowedSize();
+
         /** @brief sdbusplus DBus bus connection. */
         sdbusplus::bus::bus& bus;
 
@@ -148,6 +157,9 @@
         /** @brief Id of the last Dump entry */
         uint32_t lastEntryId;
 
+        /** @brief active dump count */
+        uint32_t activeDumpCount;
+
         /** @brief Dump main watch object */
         Watch dumpWatch;