Added space reservation

This commit is contained in:
Alexei KADIR 2024-02-20 14:54:04 +01:00
parent a260002a6c
commit af34a9c260
6 changed files with 177 additions and 7 deletions

View File

@ -177,12 +177,13 @@ result_t import_backing(char** _backing, const char* disk) {
if (info.backing_path != NULL) {
// Get the backing identifier of the parent
errno = 0;
char* backing = strdup(basename(info.backing_path));
if (backing == NULL) {
free_disk_info(&info);
remove(temp_path);
free(temp_path);
return failure("Failed to get the backing identifier of the parent.");
return failure("Failed to get the backing identifier of the parent of '%s' (%s).", disk, strerror(errno));
}
// Check that the backing exists
@ -406,13 +407,14 @@ result_t get_backing_parent(char** _parent, const char* backing) {
}
// Get the backing identifier of the parent
errno = 0;
char* parent = strdup(basename(info.backing_path));
// Free the disk info as it is not needed anymore
free_disk_info(&info);
if (parent == NULL)
return failure("Failed to get the backing identifier of the parent.");
return failure("Failed to get the backing identifier of the parent of '%s' (%s).", backing, strerror(errno));
*_parent = parent;
return success();

View File

@ -9,6 +9,8 @@
#include <unistd.h>
#include <libgen.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/types.h>
result_t check_container_identifier(const char* container) {
// Check that the container identifier is not null
@ -271,14 +273,152 @@ result_t get_container_backing(char** _backing, const char* container) {
}
// Get the backing identifier
errno = 0;
char* backing = strdup(basename(info.backing_path));
// Free the disk information as it is no longer needed
free_disk_info(&info);
if (backing == NULL)
return failure("Failed to get backing identifier for container '%s'.", container);
return failure("Failed to get backing identifier for container '%s' (%s).", container, strerror(errno));
*_backing = backing;
return success();
}
result_t get_container_info(disk_info_t* _info, const char* container) {
// Initialize the output parameters
_info->size = 0;
_info->allocated = 0;
_info->backing_path = NULL;
// Check that the container exists
result_t result = check_container_exists(container);
if (result != success())
return result;
// Get the container path
char* path;
result = get_container_path(&path, container);
if (result != success())
return result;
// Get the disk information
result = get_disk_info(_info, path);
free(path);
return result;
}
result_t get_oldest_container(char** _container) {
// Initialize the output parameters
*_container = NULL;
// List the containers
char** containers;
result_t result = list_containers(&containers);
if (result != success())
return result;
// Find the oldest container
char* oldest_container = NULL;
time_t oldest_time = 0;
for (size_t i = 0; containers[i] != NULL; i++) {
// Get the container path
char* path;
result = get_container_path(&path, containers[i]);
if (result != success())
continue;
// Get information about the container file
struct stat st;
errno = 0;
if (stat(path, &st) != 0) {
free(path);
continue;
}
// Check if the container is older than the current oldest
if (oldest_container == NULL || st.st_mtime < oldest_time) {
oldest_container = containers[i];
oldest_time = st.st_mtime;
}
}
// Duplicate the oldest container
if (oldest_container != NULL) {
errno = 0;
*_container = strdup(oldest_container);
if (*_container == NULL) {
for (size_t i = 0; containers[i] != NULL; i++)
free(containers[i]);
free(containers);
return failure("Failed to allocate memory for the oldest container (%s).", strerror(errno));
}
}
// Free the containers
for (size_t i = 0; containers[i] != NULL; i++)
free(containers[i]);
free(containers);
return success();
}
result_t get_container_pool_space(uint64_t* _space) {
// Initialize the output parameters
*_space = 0;
// Get the container pool path
char* pool_path;
result_t result = get_container_pool_path(&pool_path);
if (result != success())
return result;
// Get the space of the container pool
struct statvfs st;
errno = 0;
if (statvfs(pool_path, &st) != 0) {
free(pool_path);
return failure("Failed to get space of container pool (%s).", strerror(errno));
}
*_space = st.f_bsize * st.f_bavail;
free(pool_path);
return success();
}
result_t reserve_container_pool_space(uint64_t size) {
// As long as there is not enough space in the container pool, remove the oldest container
while (true) {
// Get the available space in the container pool
uint64_t space;
result_t result = get_container_pool_space(&space);
if (result != success())
return result;
// Check if there is enough space
if (space >= size)
return success();
// Get the oldest container
char* container;
result = get_oldest_container(&container);
if (result != success())
return result;
if (container == NULL)
return success(); // No more containers to remove
// Remove the oldest container
result = remove_container(container);
free(container);
if (result != success())
return result;
}
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "utils.h"
#include "disk.h"
#define CONTAINER_IDENTIFIER_MAX_LENGTH 64
@ -66,4 +67,25 @@ result_t list_containers(char*** _containers);
/// @param _backing The string pointer to store the resulting backing in.
/// @param container The container to get the backing of.
/// @return The result of the operation.
result_t get_container_backing(char** _backing, const char* container);
result_t get_container_backing(char** _backing, const char* container);
/// @brief Gets information about the given container. If the container does not exist, the call will return a failure result with an error message.
/// @param _info The string pointer to store the resulting disk information in. The caller is responsible for freeing the string.
/// @param container The container to get information about.
/// @return The result of the operation.
result_t get_container_info(disk_info_t* _info, const char* container);
/// @brief Gets the oldest container in the pool.
/// @param _container The string pointer to store the resulting container in. The caller is responsible for freeing the string.
/// @return The result of the operation.
result_t get_oldest_container(char** _container);
/// @brief Gets the available space in the pool.
/// @param _space The string pointer to store the resulting space in, in bytes. The caller is responsible for freeing the string.
/// @return The result of the operation.
result_t get_container_pool_space(uint64_t* _space);
/// @brief Reserves the given space in the pool. If the pool does not have enough space, the oldest containers will be removed to make space.
/// @param size The size to reserve, in bytes.
/// @return The result of the operation.
result_t reserve_container_pool_space(uint64_t size);

View File

@ -273,10 +273,11 @@ result_t get_disk_info(disk_info_t* _info, const char* path) {
}
// Duplicate the backing path string
errno = 0;
backing_path = strdup(backing_str);
if (backing_path == NULL) {
json_object_put(root);
return failure("Failed to allocate memory for the backing path.");
return failure("Failed to allocate memory for the backing path (%s).", strerror(errno));
}
}

View File

@ -67,6 +67,9 @@ int main(int argc, char** argv) {
}
// TODO: Parse commands from the command line
char* container;
get_oldest_container(&container);
printf("Oldest container: %s\n", container);
}
int command_help(int argc, char* argv[]) {

View File

@ -202,6 +202,7 @@ result_t execute(int* _exit_code, char** _stdoutbuf, char** _stderrbuf, const ch
va_start(args, executable);
for (int i = 1; i < argc; i++) {
errno = 0;
argv[i] = strdup(va_arg(args, const char*));
if (argv[i] == NULL) {
for (int j = 0; j < i; j++)
@ -511,13 +512,14 @@ result_t list_files(char*** _files, const char* path, bool (*filter)(const char*
continue;
// Add the entry to the files array
errno = 0;
files[length] = strdup(entry->d_name);
if (files[length] == NULL) {
for (size_t i = 0; i < length; i++)
free(files[i]);
free(files);
closedir(dir);
return failure("Failed to allocate memory for the file name.");
return failure("Failed to allocate memory for the file name (%s).", strerror(errno));
}
length++;