/*

 * Copyright (c) Huawei Technologies Co., Ltd. 2025-2026. All rights reserved.

 * ubs-virt-ovs is licensed under Mulan PSL v2.

 * You can use this software according to the terms and conditions of the Mulan PSL v2.

 * You may obtain a copy of Mulan PSL v2 at:

 *          http://license.coscl.org.cn/MulanPSL2

 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,

 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,

 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.

 * See the Mulan PSL v2 for more details.

 */



#include "mem_limiter.h"

#include <acl/acl.h>

#include <errno.h>

#include <runtime/rt.h>

#include <string.h>

#include <sys/stat.h>

#include "runtime_hook.h"



bool memory_check(size_t requested)

{

    size_t used = 0;

    int ret = get_mem_used(&used);

    CHECK_COND_RETURN_(ret != 0, false, "get mem used failed.");

    size_t quota = get_mem_limit_quota();

    size_t total;

    bool result = __builtin_add_overflow(requested, used, &total);

    CHECK_COND_RETURN_(result, false, "User requested mem size too big! Request:%zu B, used:%zu B, quota:%zu B.",

                       requested, used, quota);

    CHECK_COND_RETURN_((total > quota), false, "Out of memory! Request:%zu B, used:%zu B, quota:%zu B.", requested,

                       used, quota);

    return true;

}



int guard_memory(size_t requested)

{

    file_lock lock = file_lock_create(lock_path(), LOCK_EX);

    if (!file_lock_isvalid(&lock)) {

        LOG_ERROR("Guard memory failed to create file lock!");

        file_lock_destroy(&lock);

        return ACL_ERROR_FAILURE;

    }



    if (!memory_check(requested)) {

        LOG_ERROR("Guard memory out of memory error for requested:%zd", requested);

        file_lock_destroy(&lock);

        return ACL_ERROR_STORAGE_OVER_LIMIT;

    }

    file_lock_destroy(&lock);

    return ENPU_SUCCESS;

}



const char *lock_path()

{

    return MEMCTL_LOCK_PATH;

}



int create_file_lock_base_dir()

{

    char cmd[128];

    int ans = snprintf_s(cmd, sizeof(cmd), sizeof(cmd), "mkdir -p -m 750 %s", FILE_LOCK_BASE_DIR);

    CHECK_COND_RETURN_ERROR_CODE(ans < 0, "Can not concatenate string to create dir.");

    int ret = system(cmd);

    CHECK_COND_RETURN_ERROR_CODE(ret < 0 && errno != EEXIST, "create %s failed, err is %s.", FILE_LOCK_BASE_DIR,

                                 strerror(errno));



    LOG_INFO("create %s success", FILE_LOCK_BASE_DIR);

    return ENPU_SUCCESS;

}



int memory_limiter_init()

{

    return create_file_lock_base_dir();

}