LCOV - code coverage report
Current view: top level - aicpu_schedule/core - aicpusd_cust_so_manager.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 93.3 % 477 445
Test Date: 2026-08-12 11:05:02 Functions: 100.0 % 37 37

            Line data    Source code
       1              : /**
       2              :  * Copyright (c) 2025 Huawei Technologies Co., Ltd.
       3              :  * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
       4              :  * CANN Open Software License Agreement Version 2.0 (the "License").
       5              :  * Please refer to the License for details. You may not use this file except in compliance with the License.
       6              :  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
       7              :  * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
       8              :  * See LICENSE in the root of the software repository for the full text of the License.
       9              :  */
      10              : #include "aicpusd_cust_so_manager.h"
      11              : 
      12              : #include <fstream>
      13              : #include <cstring>
      14              : #include <dirent.h>
      15              : #include <errno.h>
      16              : #include <unistd.h>
      17              : #include <securec.h>
      18              : #include <sys/stat.h>
      19              : #include <sys/file.h>
      20              : #include <sys/types.h>
      21              : #include "aicpu_engine.h"
      22              : #include "aicpusd_status.h"
      23              : #include "aicpusd_info.h"
      24              : #include "aicpu_event_struct.h"
      25              : #include "common/aicpusd_util.h"
      26              : #include "core/aicpusd_drv_manager.h"
      27              : #include "aicpusd_feature_ctrl.h"
      28              : 
      29              : namespace {
      30              : // cust so root path: CustAiCpuUser
      31              : const std::string CP_CUSTOM_SO_ROOT_PATH = "/home/CustAiCpuUser";
      32              : const std::string CP_CUSTOM_SO_LIB_NAME = "lib/";
      33              : const std::string CP_CUSTOM_SO_LOCK_NAME = "lib_locker";
      34              : // prefix of cust so dir name
      35              : constexpr const char* CP_CUSTOM_SO_DIR_NAME_PREFIX = "cust_aicpu_";
      36              : // pattern for custom so name
      37              : constexpr const char* CP_PATTERN_FOR_SO_NAME("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890-_.");
      38              : constexpr const uint32_t DIV_NUM = 2U;
      39              : // physical machine VFID == 0 物理机场景
      40              : constexpr uint32_t CP_DEFAULT_VF_ID = 0U;
      41              : // permissions
      42              : constexpr uint32_t READ_OWNER = 256U;
      43              : constexpr uint32_t WRITE_OWNER = 128U;
      44              : constexpr uint32_t EXEC_OWNER = 64U;
      45              : constexpr uint32_t READ_GROUP = 32U;
      46              : constexpr uint32_t EXEC_GROUP = 8U;
      47              : constexpr uint64_t MAX_FILE_SIZE = 0xc800000; // 200MB
      48              : 
      49              : // permissions to 640
      50              : constexpr mode_t MODE_640 =
      51              :     static_cast<mode_t>(READ_OWNER) | static_cast<mode_t>(WRITE_OWNER) | static_cast<mode_t>(READ_GROUP);
      52              : // permissions to 750
      53              : constexpr mode_t MODE_750 = static_cast<mode_t>(READ_OWNER) | static_cast<mode_t>(WRITE_OWNER) |
      54              :                             static_cast<mode_t>(EXEC_OWNER) | static_cast<mode_t>(READ_GROUP) |
      55              :                             static_cast<mode_t>(EXEC_GROUP);
      56              : } // namespace
      57              : 
      58              : namespace AicpuSchedule {
      59          123 : AicpuCustSoManager& AicpuCustSoManager::GetInstance()
      60              : {
      61          123 :     static AicpuCustSoManager instance;
      62          123 :     return instance;
      63              : }
      64              : 
      65           37 : int32_t AicpuCustSoManager::InitAicpuCustSoManager(const aicpu::AicpuRunMode mode, const AicpuSchedMode schedMode)
      66              : {
      67           37 :     runMode_ = mode;
      68           37 :     schedMode_ = schedMode;
      69           37 :     (void)GetDirForCustAicpuSo(custSoRootPath_);
      70              :     // init cust so soft link path
      71           37 :     custSoDirName_ = GetPathForCustAicpuSoftLink();
      72           37 :     if (runMode_ == aicpu::AicpuRunMode::PROCESS_PCIE_MODE) {
      73            3 :         hashCalculator_.SetSoRootPath(custSoRootPath_);
      74            3 :         fileLocker_.InitFileLocker(custSoRootPath_ + CP_CUSTOM_SO_LOCK_NAME);
      75              :     }
      76              : 
      77           37 :     aicpusd_run_info(
      78              :         "Cust so manager init successfully, dir=%s, runMode=%u, schedMode=%u.", custSoDirName_.c_str(),
      79              :         static_cast<uint32_t>(runMode_), static_cast<uint32_t>(schedMode));
      80           37 :     return AICPU_SCHEDULE_OK;
      81              : }
      82              : 
      83           31 : bool AicpuCustSoManager::IsSupportCustAicpu() const
      84              : {
      85              :     // msgq mode does not support cust aicpu
      86           31 :     if (schedMode_ == SCHED_MODE_MSGQ) {
      87            3 :         return false;
      88              :     }
      89           28 :     return true;
      90              : }
      91              : 
      92           28 : int32_t AicpuCustSoManager::CheckAndCreateSoFile(const LoadOpFromBufArgs* const args, std::string& soName)
      93              : {
      94              :     // check init result
      95           28 :     if (!CheckCustSoPath()) {
      96            1 :         return AICPU_SCHEDULE_ERROR_INNER_ERROR;
      97              :     }
      98              : 
      99           27 :     if (args == nullptr) {
     100            1 :         aicpusd_err("cust so ptr is null.");
     101            1 :         return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     102              :     }
     103              :     // check so buf
     104           26 :     char_t* const soBuf = PtrToPtr<void, char_t>(ValueToPtr(args->kernelSoBuf));
     105           26 :     if (soBuf == nullptr) {
     106            1 :         aicpusd_err("BatchLoadOpFromBuf kernel so buf ptr is null.");
     107            1 :         return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     108              :     }
     109              :     // check so buf len
     110           25 :     const uint32_t soBufLen = static_cast<uint32_t>(args->kernelSoBufLen);
     111           25 :     if (soBufLen == 0U) {
     112            3 :         aicpusd_err("BatchLoadOpFromBuf kernel input param soBufLen must > 0");
     113            3 :         return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     114              :     }
     115              :     // check so name
     116           22 :     const char_t* const soNamePtr = static_cast<const char_t*>(ValueToPtr(args->kernelSoName));
     117           22 :     if (soNamePtr == nullptr) {
     118            1 :         aicpusd_err("BatchLoadOpFromBuf kernel so name ptr is null.");
     119            1 :         return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     120              :     }
     121              :     // check so name len
     122           21 :     const uint32_t soNameLen = static_cast<uint32_t>(args->kernelSoNameLen);
     123           21 :     if ((soNameLen == 0U) || (soNameLen > MAX_CUST_SO_NAME_LEN)) {
     124            1 :         aicpusd_err(
     125              :             "BatchLoadOpFromBuf kernel input param soNameLen=%u not in (0, %u].", soNameLen, MAX_CUST_SO_NAME_LEN);
     126            1 :         return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     127              :     }
     128              : 
     129              :     // crate so file
     130           20 :     const std::string realSoName(soNamePtr, static_cast<size_t>(soNameLen));
     131           20 :     const FileInfo fileInfo = {.data = soBuf, .size = soBufLen, .name = realSoName};
     132           20 :     const int32_t ret = CreateSoFile(fileInfo);
     133           20 :     if (ret != AICPU_SCHEDULE_OK) {
     134            3 :         aicpusd_err("Process BatchLoadOpFromBuf failed as parse so file failed, so name[%s].", realSoName.c_str());
     135            3 :         return ret;
     136              :     }
     137           17 :     soName = realSoName;
     138           17 :     return AICPU_SCHEDULE_OK;
     139           20 : }
     140              : 
     141           18 : int32_t AicpuCustSoManager::CheckAndDeleteSoFile(const LoadOpFromBufArgs* const args)
     142              : {
     143              :     // check init result
     144           18 :     if (!CheckCustSoPath()) {
     145            1 :         aicpusd_err("Check cust so path fail");
     146            1 :         return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     147              :     }
     148              : 
     149           17 :     if (args == nullptr) {
     150            1 :         aicpusd_err("cust so ptr is null.");
     151            1 :         return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     152              :     }
     153              :     // check so name len
     154           16 :     const uint32_t soNameLen = static_cast<uint32_t>(args->kernelSoNameLen);
     155           16 :     if ((soNameLen == 0U) || (soNameLen > MAX_CUST_SO_NAME_LEN)) {
     156            2 :         aicpusd_err("LoadOpFromBuf kernel input param soNameLen=%u not in (0, %u].", soNameLen, MAX_CUST_SO_NAME_LEN);
     157            2 :         return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     158              :     }
     159              :     // check so name
     160           14 :     if (args->kernelSoName == 0U) {
     161            1 :         aicpusd_err("so name ptr is null.");
     162            1 :         return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     163              :     }
     164              :     const std::string realSoName(
     165           13 :         static_cast<const char_t*>(ValueToPtr(args->kernelSoName)), static_cast<size_t>(soNameLen));
     166           13 :     if (realSoName.find_first_not_of(CP_PATTERN_FOR_SO_NAME) != std::string::npos) {
     167            1 :         aicpusd_err("Cust so name %s is not invalid. Please check!", realSoName.c_str());
     168            1 :         return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     169              :     }
     170              : 
     171           12 :     std::string fileName;
     172           12 :     (void)fileName.append(custSoDirName_).append(std::string(realSoName));
     173           12 :     if (access(fileName.c_str(), F_OK) != 0) {
     174            9 :         aicpusd_run_warn("Check deleteCustOp's so full path:%s failed, error:%s", fileName.c_str(), strerror(errno));
     175            9 :         return AICPU_SCHEDULE_OK;
     176              :     }
     177              :     // check so file
     178            3 :     const int32_t ret = CheckSoFullPathValid(fileName);
     179            3 :     if (ret != AICPU_SCHEDULE_OK) {
     180            1 :         return ret;
     181              :     }
     182              : 
     183              :     // delete so
     184            2 :     return DeleteSoFile(custSoDirName_, fileName);
     185           13 : }
     186              : 
     187            7 : int32_t AicpuCustSoManager::CheckAndDeleteCustSoDir()
     188              : {
     189              :     // check init result
     190            7 :     if (!CheckCustSoPath()) {
     191            1 :         return AICPU_SCHEDULE_OK;
     192              :     }
     193              : 
     194            6 :     const std::string dirName(custSoDirName_);
     195              :     // check whether dir is empty. If empty, delete dir
     196              :     {
     197            6 :         const std::lock_guard<std::mutex> soFileLock(soFileMutex_);
     198            6 :         if (CheckDirEmpty(dirName)) {
     199            2 :             if (remove(dirName.c_str()) != 0) {
     200            1 :                 aicpusd_run_info("Delete dir:%s failed, error is %s.", dirName.c_str(), strerror(errno));
     201              :             } else {
     202            1 :                 aicpusd_info("Delete dir:%s success.", dirName.c_str());
     203              :             }
     204              :         }
     205            6 :     }
     206            6 :     return AICPU_SCHEDULE_OK;
     207            6 : }
     208              : 
     209           14 : int32_t AicpuCustSoManager::CreateSoFile(const FileInfo& fileInfo)
     210              : {
     211           14 :     aicpusd_info("begin to create so file. soName is %s", fileInfo.name.c_str());
     212              :     // check so name
     213           14 :     const std::string kernelSo(fileInfo.name);
     214           14 :     if (kernelSo.find_first_not_of(CP_PATTERN_FOR_SO_NAME) != std::string::npos) {
     215            1 :         aicpusd_err("Cust so name %s is not invalid. Please check!", kernelSo.c_str());
     216            1 :         return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     217              :     }
     218              : 
     219           13 :     const int32_t ret = DoCreateSoFile(fileInfo);
     220           13 :     if (ret != AICPU_SCHEDULE_OK) {
     221            4 :         aicpusd_err("Create so failed, path=%s", fileInfo.name.c_str());
     222            4 :         return ret;
     223              :     }
     224              : 
     225              :     // load so if current aicpu mode is thread mode(minirc/ctrlcpu/lhisi)
     226            9 :     if (runMode_ == aicpu::AicpuRunMode::THREAD_MODE) {
     227            7 :         const uint32_t loadSoNum = 1U;
     228            7 :         const char* soNames[loadSoNum] = {fileInfo.name.c_str()};
     229            7 :         (void)aeBatchLoadKernelSo(aicpu::KERNEL_TYPE_AICPU_CUSTOM, loadSoNum, &(soNames[0]));
     230              :     }
     231            9 :     aicpusd_info("Create so file %s success", fileInfo.name.c_str());
     232            9 :     return AICPU_SCHEDULE_OK;
     233           14 : }
     234              : 
     235           13 : int32_t AicpuCustSoManager::DoCreateSoFile(const FileInfo& fileInfo)
     236              : {
     237           13 :     const std::lock_guard<std::mutex> soFileLock(soFileMutex_);
     238           13 :     const std::string softLinkPath = custSoDirName_ + fileInfo.name;
     239           13 :     if (runMode_ != aicpu::AicpuRunMode::PROCESS_PCIE_MODE) {
     240            8 :         aicpusd_info("Aicpu is not process mode, only write file. path=%s", softLinkPath.c_str());
     241            8 :         const FileInfo newFileInfo = {.data = fileInfo.data, .size = fileInfo.size, .name = softLinkPath};
     242            8 :         return WriteBufToSoFile(newFileInfo, GetPathForCustAicpuSoftLink());
     243            8 :     }
     244              : 
     245            5 :     int32_t ret = AICPU_SCHEDULE_OK;
     246            5 :     FileHashInfo existedFileInfo = {};
     247            5 :     const std::string soFullPath = GenerateSoFullPath(fileInfo.name); // The real so name, not is soft link
     248            5 :     const FileInfo newFileInfo = {.data = fileInfo.data, .size = fileInfo.size, .name = soFullPath};
     249            5 :     fileLocker_.LockFileLocker();
     250            5 :     if (hashCalculator_.GetSameFileInfo(newFileInfo, existedFileInfo)) {
     251            4 :         ret = CreateSoftLinkToSoFile(softLinkPath, existedFileInfo.filePath);
     252              :     } else {
     253            1 :         ret = WriteBufToSoFile(newFileInfo, GetPathForCustAicpuRealSo());
     254            1 :         if (ret == AICPU_SCHEDULE_OK) {
     255            0 :             ret = CreateSoftLinkToSoFile(softLinkPath, soFullPath);
     256              :         }
     257              :     }
     258            5 :     fileLocker_.UnlockFileLocker();
     259            5 :     if (ret != AICPU_SCHEDULE_OK) {
     260            3 :         aicpusd_err("Create so file failed, so=%s", softLinkPath.c_str());
     261            3 :         return ret;
     262              :     }
     263              : 
     264            2 :     return ret;
     265           13 : }
     266              : 
     267           13 : int32_t AicpuCustSoManager::WriteBufToSoFile(const FileInfo& fileInfo, const std::string& dirPath) const
     268              : {
     269           13 :     const std::string soName = fileInfo.name;
     270              :     // check and make dir
     271           13 :     int32_t ret = CheckOrMakeDirectory(dirPath);
     272           13 :     if (ret != 0) {
     273            0 :         aicpusd_err("Check or create directory:%s failed.", dirPath.c_str());
     274            0 :         return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     275              :     }
     276              :     // serious security problem, must check realpath
     277           13 :     ret = CheckSoFullPathValid(soName);
     278           13 :     if (ret != AICPU_SCHEDULE_OK) {
     279            3 :         return ret;
     280              :     }
     281              :     // check whether so exist
     282           10 :     if (access(soName.c_str(), F_OK) == 0) {
     283            1 :         aicpusd_info("%s already exists in the current directory, no need to write again.", soName.c_str());
     284            1 :         return AICPU_SCHEDULE_OK;
     285              :     }
     286              :     try {
     287            9 :         std::ofstream soFile(soName, std::ios::out | std::ios::binary);
     288            9 :         if (!soFile) {
     289            1 :             aicpusd_err("Fail to open file:%s. reason=%s", soName.c_str(), strerror(errno));
     290            1 :             return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     291              :         }
     292           16 :         const ScopeGuard fileGuard([&soFile]() { soFile.close(); });
     293            8 :         (void)soFile.write(fileInfo.data, static_cast<std::streamsize>(fileInfo.size));
     294            8 :         if (!soFile.good()) {
     295            0 :             aicpusd_err(
     296              :                 "Fail to write file:%s, length:%u, eof=%d, bad=%d, fail=%d, reason=%s. please check host so size",
     297              :                 soName.c_str(), fileInfo.size, soFile.eof(), soFile.bad(), soFile.fail(), strerror(errno));
     298            0 :             return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     299              :         }
     300            8 :         soFile.flush();
     301            8 :         if (!soFile.good()) {
     302            1 :             aicpusd_err(
     303              :                 "Fail to flush file:%s, length:%u, eof=%d, bad=%d, fail=%d, reason=%s. please check host so size",
     304              :                 soName.c_str(), fileInfo.size, soFile.eof(), soFile.bad(), soFile.fail(), strerror(errno));
     305            1 :             return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     306              :         }
     307           10 :     } catch (const std::ofstream::failure& err) {
     308            0 :         aicpusd_err("Fail to write file:%s, err=%s, reason=%s.", soName.c_str(), err.what(), strerror(errno));
     309            0 :         return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     310            0 :     }
     311              :     // change so file permissions to 640
     312            7 :     if (chmod(soName.c_str(), MODE_640) != 0) {
     313            0 :         aicpusd_err("Change file:%s mode failed.", soName.c_str());
     314            0 :         return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     315              :     }
     316            7 :     const uint64_t hashValue = HashCalculator::GetQuickHash(fileInfo.data, fileInfo.size);
     317            7 :     aicpusd_run_info(
     318              :         "Write buffer to so success, path=%s, hash=%llu, fileSize=%zu", soName.c_str(), hashValue, fileInfo.size);
     319            7 :     return AICPU_SCHEDULE_OK;
     320           13 : }
     321              : 
     322            4 : int32_t AicpuCustSoManager::CreateSoftLinkToSoFile(const std::string& softLinkPath, const std::string& existedSoPath)
     323              : {
     324            4 :     if (access(existedSoPath.c_str(), F_OK) != 0) {
     325            1 :         aicpusd_err(
     326              :             "The target path is not existed in device, cannot create. linkPath=%s, targetPath=%s", softLinkPath.c_str(),
     327              :             existedSoPath.c_str());
     328            1 :         return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     329              :     }
     330              : 
     331            3 :     if (access(softLinkPath.c_str(), F_OK) == 0) {
     332            1 :         aicpusd_info(
     333              :             "The soft link has existed in device, cannot create again. linkPath=%s, targetPath=%s",
     334              :             softLinkPath.c_str(), existedSoPath.c_str());
     335            1 :         return AICPU_SCHEDULE_OK;
     336              :     }
     337              : 
     338            2 :     int32_t ret = CheckOrMakeDirectory(custSoDirName_);
     339            2 :     if (ret != AICPU_SCHEDULE_OK) {
     340            1 :         aicpusd_err("The dir to create so soft link is not exist, dir=%s", custSoDirName_.c_str());
     341            1 :         return ret;
     342              :     }
     343              : 
     344            1 :     ret = CheckSoFullPathValid(softLinkPath);
     345            1 :     if (ret != AICPU_SCHEDULE_OK) {
     346            0 :         aicpusd_err("Invalid soft link path, linkPath=%s, targetPath=%s", softLinkPath.c_str(), existedSoPath.c_str());
     347            0 :         return ret;
     348              :     }
     349              : 
     350            1 :     ret = symlink(existedSoPath.c_str(), softLinkPath.c_str());
     351            1 :     if (ret != 0) {
     352            0 :         aicpusd_err(
     353              :             "Create soft links failed, ret=%d, linkPath=%s, targetPath=%s, reason=%s", ret, softLinkPath.c_str(),
     354              :             existedSoPath.c_str(), strerror(errno));
     355            0 :         return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     356              :     }
     357              : 
     358            1 :     aicpusd_run_info(
     359              :         "Create soft link so success, linkPath=%s, targetPath=%s", softLinkPath.c_str(), existedSoPath.c_str());
     360            1 :     return AICPU_SCHEDULE_OK;
     361              : }
     362              : 
     363           40 : int32_t AicpuCustSoManager::GetDirForCustAicpuSo(std::string& dirName) const
     364              : {
     365           40 :     const uint32_t uniqueVfId = AicpuDrvManager::GetInstance().GetUniqueVfId();
     366           40 :     if (runMode_ == aicpu::AicpuRunMode::PROCESS_PCIE_MODE) {
     367            4 :         dirName = GetCustAicpuUserPath(uniqueVfId);
     368              :     } else {
     369              :         // get cust aicpu so path
     370           36 :         bool envRet = false;
     371           36 :         std::string custDirName = "";
     372           36 :         if (runMode_ == aicpu::AicpuRunMode::THREAD_MODE) {
     373           31 :             envRet = AicpuUtil::GetEnvVal(ENV_NAME_CUST_SO_PATH, custDirName);
     374              :         }
     375           36 :         if (!envRet) {
     376           35 :             envRet = AicpuUtil::GetEnvVal(ENV_NAME_HOME, custDirName);
     377           35 :             if (!envRet) {
     378            1 :                 aicpusd_info("Getting current home directory was not successful.");
     379            1 :                 return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     380              :             }
     381              :         }
     382              : 
     383           35 :         dirName = custDirName;
     384           35 :         const size_t len = dirName.size();
     385           35 :         if ((len == 0U) || (len >= static_cast<size_t>(PATH_MAX))) {
     386            1 :             aicpusd_err("The length of custDirName is %zu which is invalid.", len);
     387            1 :             return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     388              :         }
     389           34 :         if (dirName[dirName.size() - 1U] != '/') {
     390           34 :             (void)dirName.append("/");
     391              :         }
     392           36 :     }
     393              : 
     394              :     // check directory ${customUser} or ${currentUser}
     395           38 :     const int ret = access(dirName.c_str(), F_OK);
     396           38 :     if (ret != 0) {
     397            4 :         aicpusd_err("Check directory:%s failed, error is %s.", dirName.c_str(), strerror(errno));
     398            4 :         return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     399              :     }
     400              : 
     401           34 :     return AICPU_SCHEDULE_OK;
     402              : }
     403              : 
     404            4 : std::string AicpuCustSoManager::GetCustAicpuUserPath(const uint32_t uniqueVfId) const
     405              : {
     406              :     // dc: ${CustAicpuUser${vfId}}/cust_aicpu_vf${vfId}/cust_aicpu_pid${hostpid}/
     407              :     // vfId is equal to 0, user is CustAicpuUser, other are CustAicpuUser${vfId}
     408            4 :     std::string dirName = CP_CUSTOM_SO_ROOT_PATH;
     409            4 :     if (uniqueVfId == CP_DEFAULT_VF_ID) {
     410            1 :         (void)dirName.append("/");
     411            3 :     } else if (FeatureCtrl::IsVfModeCheckedByDeviceId(uniqueVfId)) {
     412            2 :         const uint32_t custNum = (uniqueVfId - VDEVICE_MIN_CPU_NUM) / DIV_NUM + 1;
     413            2 :         (void)dirName.append(std::to_string(custNum)).append("/");
     414              :     } else {
     415            1 :         (void)dirName.append(std::to_string(uniqueVfId)).append("/");
     416              :     }
     417              : 
     418            4 :     return dirName;
     419            0 : }
     420              : 
     421            6 : std::string AicpuCustSoManager::GetPathForCustAicpuRealSo() const { return custSoRootPath_ + CP_CUSTOM_SO_LIB_NAME; }
     422              : 
     423           45 : std::string AicpuCustSoManager::GetPathForCustAicpuSoftLink() const
     424              : {
     425           45 :     const uint32_t uniqueVfId = AicpuDrvManager::GetInstance().GetUniqueVfId();
     426           45 :     std::string dirName = custSoRootPath_;
     427           45 :     const uint32_t deviceId = AicpuDrvManager::GetInstance().GetDeviceId();
     428           45 :     const pid_t hostPid = AicpuDrvManager::GetInstance().GetHostPid();
     429           45 :     (void)dirName.append(CP_CUSTOM_SO_DIR_NAME_PREFIX)
     430           45 :         .append(std::to_string(deviceId))
     431           45 :         .append("_")
     432           90 :         .append(std::to_string(uniqueVfId))
     433           45 :         .append("_")
     434           90 :         .append(std::to_string(static_cast<int32_t>(hostPid)))
     435           45 :         .append("/");
     436           45 :     return dirName;
     437            0 : }
     438              : 
     439            9 : int32_t AicpuCustSoManager::CheckSoFullPathValid(const std::string& soFullPath) const
     440              : {
     441            9 :     if (soFullPath.length() >= static_cast<size_t>(PATH_MAX)) {
     442            1 :         aicpusd_err("soFullPath file length[%zu] must less than PATH_MAX[%u]", soFullPath.length(), PATH_MAX);
     443            1 :         return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     444              :     }
     445              : 
     446            8 :     const std::string::size_type pos = soFullPath.rfind('/');
     447            8 :     if (pos == std::string::npos) {
     448            4 :         aicpusd_err("The path of current so file %s does not contain /.", soFullPath.c_str());
     449            4 :         return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     450              :     }
     451              :     // include last '/'
     452            4 :     const std::string realFilePath = soFullPath.substr(0U, pos + 1U);
     453              : 
     454            4 :     std::unique_ptr<char_t[]> path(new (std::nothrow) char_t[PATH_MAX]);
     455            4 :     if (path == nullptr) {
     456            0 :         aicpusd_run_info("Alloc memory for path failed.");
     457            0 :         return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     458              :     }
     459              : 
     460            4 :     const auto eRet = memset_s(path.get(), PATH_MAX, 0, PATH_MAX);
     461            4 :     if (eRet != EOK) {
     462            1 :         aicpusd_run_info("Mem set was not successful, ret=%d", eRet);
     463            1 :         return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     464              :     }
     465              : 
     466            3 :     if (realpath(realFilePath.data(), path.get()) == nullptr) {
     467            1 :         aicpusd_err("Format to realpath failed:%s, path:%s", realFilePath.c_str(), path.get());
     468            1 :         return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     469              :     }
     470              :     // path after realpath
     471            2 :     std::string normalizedPath(path.get());
     472            2 :     if (normalizedPath[normalizedPath.length() - 1U] != '/') {
     473            2 :         (void)normalizedPath.append("/");
     474              :     }
     475              : 
     476            2 :     if (normalizedPath != realFilePath) {
     477            0 :         aicpusd_err("Invalid so file:%s, should be %s", realFilePath.c_str(), normalizedPath.c_str());
     478            0 :         return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     479              :     }
     480            2 :     aicpusd_info("check so file %s success.", soFullPath.c_str());
     481            2 :     return AICPU_SCHEDULE_OK;
     482            4 : }
     483              : 
     484           12 : int32_t AicpuCustSoManager::CheckOrMakeDirectory(const std::string& dirName) const
     485              : {
     486              :     // input dirName is checked to be not nullptr
     487           12 :     int32_t ret = access(dirName.c_str(), F_OK);
     488           12 :     if (ret == -1) {
     489              :         // create directory and set permissions to 750
     490           10 :         ret = mkdir(dirName.c_str(), MODE_750);
     491           10 :         if (ret == -1) {
     492            1 :             const std::string errMsg = "Create directory:" + dirName + " failed, error:" + strerror(errno);
     493            1 :             aicpusd_err("%s", errMsg.c_str());
     494            1 :             return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     495            1 :         }
     496            9 :         ret = chmod(dirName.c_str(), MODE_750);
     497            9 :         if (ret != 0) {
     498            1 :             aicpusd_err("Change directory:%s mode failed, errno:%s.", dirName.c_str(), strerror(errno));
     499            1 :             return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     500              :         }
     501              :     }
     502           10 :     return AICPU_SCHEDULE_OK;
     503              : }
     504              : 
     505            7 : bool AicpuCustSoManager::CheckDirEmpty(const std::string& dirName) const
     506              : {
     507              :     // open dir
     508            7 :     DIR* const dirHandle = opendir(dirName.c_str());
     509            7 :     if (dirHandle == nullptr) {
     510            5 :         aicpusd_err("Open dir:%s failed, error:%s.", dirName.c_str(), strerror(errno));
     511            5 :         return false;
     512              :     }
     513              :     // search dir
     514            2 :     dirent* ent = nullptr;
     515            5 :     while ((ent = readdir(dirHandle)) != nullptr) {
     516              :         // check whether . or ..
     517            3 :         if ((strcmp(".", ent->d_name) == 0) || (strcmp("..", ent->d_name) == 0)) {
     518            2 :             continue;
     519              :         }
     520              :         // if exist dir or file, return false
     521            1 :         const int32_t dType = static_cast<int32_t>(ent->d_type);
     522            1 :         if ((dType == DT_DIR) || (dType == DT_REG)) {
     523              :             // filter hidden file
     524              :             // If so is dlopen but not dlclose, a hidden file will be created when delete the so
     525            1 :             if (ent->d_name[0] != '.') {
     526            0 :                 aicpusd_info("Dir:%s is not empty, file name is %s.", dirName.c_str(), ent->d_name);
     527            0 :                 (void)closedir(dirHandle);
     528            0 :                 return false;
     529              :             } else {
     530            1 :                 aicpusd_run_info("Exist hidden file %s in dir:%s.", ent->d_name, dirName.c_str());
     531              :             }
     532              :         }
     533              :     }
     534            2 :     (void)closedir(dirHandle);
     535            2 :     aicpusd_info("Dir:%s is empty", dirName.c_str());
     536            2 :     return true;
     537              : }
     538              : 
     539            4 : int32_t AicpuCustSoManager::DeleteCustSoDir() const
     540              : {
     541            4 :     if (custSoDirName_.empty()) {
     542            1 :         return AICPU_SCHEDULE_OK;
     543              :     }
     544              : 
     545            3 :     if (access(custSoDirName_.c_str(), F_OK) != 0) {
     546            1 :         aicpusd_run_info(
     547              :             "Accessing cust so dir %s was not successful, reason is %s.", custSoDirName_.c_str(), strerror(errno));
     548            1 :         return AICPU_SCHEDULE_OK;
     549              :     }
     550            2 :     const std::string command = "rm -rf " + custSoDirName_;
     551              : 
     552            2 :     const int32_t ret = AicpuUtil::ExecuteCmd(command.c_str());
     553            2 :     if (ret != 0) {
     554            0 :         aicpusd_err("Delete cust so dir %s failed, error is %s.", custSoDirName_.c_str(), strerror(errno));
     555            0 :         return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     556              :     }
     557            2 :     return AICPU_SCHEDULE_OK;
     558            2 : }
     559              : 
     560            4 : int32_t AicpuCustSoManager::DeleteSoFile(const std::string& dirName, const std::string& soFullPath)
     561              : {
     562            4 :     const std::lock_guard<std::mutex> soFileLock(soFileMutex_);
     563            4 :     const int32_t ret = RemoveSoFile(dirName, soFullPath);
     564            4 :     if (ret != AICPU_SCHEDULE_OK) {
     565            1 :         return ret;
     566              :     }
     567              :     // in delete so process, cannot dlclose so, because current cust so may be use some third party library,
     568              :     // the third party library may use pthread_key_create to register destruct call back for current thread when
     569              :     // dlopen, if we dlclose the so, the destruct will get invalid pointer and cause coredump
     570            3 :     return AICPU_SCHEDULE_OK;
     571            4 : }
     572              : 
     573            5 : int32_t AicpuCustSoManager::RemoveSoFile(const std::string& dirName, const std::string& soFullPath) const
     574              : {
     575            5 :     if (access(soFullPath.c_str(), F_OK) != 0) {
     576            1 :         aicpusd_info("%s not exists in the current directory, reason:%s.", soFullPath.c_str(), strerror(errno));
     577            1 :         return AICPU_SCHEDULE_OK;
     578              :     }
     579            4 :     if (chmod(dirName.c_str(), MODE_750) != 0) {
     580            1 :         aicpusd_err("Change deleteCustOp's directory:%s mode failed, error:%s.", dirName.c_str(), strerror(errno));
     581            1 :         return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     582              :     }
     583              : 
     584            3 :     if (remove(soFullPath.c_str()) != 0) {
     585            1 :         aicpusd_err("Delete so of custom op:%s failed, error:%s.", soFullPath.c_str(), strerror(errno));
     586            1 :         return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     587              :     }
     588            2 :     return AICPU_SCHEDULE_OK;
     589              : }
     590              : 
     591           51 : bool AicpuCustSoManager::CheckCustSoPath() const
     592              : {
     593           51 :     if (custSoDirName_.empty()) {
     594            3 :         aicpusd_err("custSoDirName_ is empty. Please check log of init method.");
     595            3 :         return false;
     596              :     }
     597           48 :     return true;
     598              : }
     599              : 
     600            5 : std::string AicpuCustSoManager::GenerateSoFullPath(const std::string& soName) const
     601              : {
     602              :     // Use pid to avoid same so name
     603            5 :     const pid_t hostPid = AicpuDrvManager::GetInstance().GetHostPid();
     604            5 :     const uint32_t uniqueVfId = AicpuDrvManager::GetInstance().GetUniqueVfId();
     605            5 :     const uint32_t deviceId = AicpuDrvManager::GetInstance().GetDeviceId();
     606           10 :     return GetPathForCustAicpuRealSo() + soName + "." + std::to_string(deviceId) + "." + std::to_string(uniqueVfId) +
     607           15 :            "." + std::to_string(hostPid);
     608              : }
     609              : 
     610            5 : bool HashCalculator::GetSameFileInfo(const FileInfo& fileInfo, FileHashInfo& existedFileHashInfo)
     611              : {
     612            5 :     UpdateCache();
     613              : 
     614            5 :     const uint64_t hashValue = GetQuickHash(fileInfo.data, fileInfo.size);
     615            5 :     if (GetSameHashFileFromCache(hashValue, existedFileHashInfo)) {
     616            4 :         aicpusd_info(
     617              :             "The file has same existed file after hash compare, so=%s, hash=%lu", fileInfo.name.c_str(), hashValue);
     618            4 :         return true;
     619              :     }
     620              : 
     621            1 :     FileHashInfo hashInfo = {};
     622            1 :     hashInfo.filePath = fileInfo.name;
     623            1 :     hashInfo.fileSize = fileInfo.size;
     624            1 :     hashInfo.hashValue = hashValue;
     625            1 :     AddHashInfoToCache(hashInfo);
     626              : 
     627            1 :     return false;
     628            1 : }
     629              : 
     630            7 : void HashCalculator::UpdateCache()
     631              : {
     632            7 :     std::vector<std::string> file_names = {};
     633            7 :     int32_t ret = GetFileNameInDir(file_names);
     634            7 :     if (ret != AICPU_SCHEDULE_OK) {
     635            0 :         aicpusd_warn("Get file name in dir failed");
     636            0 :         return;
     637              :     }
     638              : 
     639            9 :     for (const auto& file_name : file_names) {
     640            2 :         const std::string filePath = soRootPath_ + CP_CUSTOM_SO_LIB_NAME + file_name;
     641            2 :         if (IsFileInCache(filePath)) {
     642            1 :             continue;
     643              :         }
     644              : 
     645            1 :         aicpusd_info("Start to read so %s", filePath.c_str());
     646            1 :         FileHashInfo hashInfo = {};
     647            1 :         ret = GenerateFileHashInfo(filePath, hashInfo);
     648            1 :         if (ret != AICPU_SCHEDULE_OK) {
     649            0 :             aicpusd_err("Get file hash info failed, filePath=%s", filePath.c_str());
     650              :         } else {
     651            1 :             AddHashInfoToCache(hashInfo);
     652              :         }
     653            2 :     }
     654            7 : }
     655              : 
     656            5 : bool HashCalculator::GetSameHashFileFromCache(const uint64_t hashValue, FileHashInfo& existedFileHashInfo) const
     657              : {
     658            5 :     for (const auto& hashInfo : cache_) {
     659            4 :         if (hashValue == hashInfo.hashValue) {
     660            4 :             existedFileHashInfo = hashInfo;
     661            4 :             return true;
     662              :         }
     663              :     }
     664              : 
     665            1 :     return false;
     666              : }
     667              : 
     668            4 : int32_t HashCalculator::GenerateFileHashInfo(const std::string& filePath, FileHashInfo& hashInfo) const
     669              : {
     670            4 :     if (!IsFileExist(filePath) || !IsRegularFile(filePath)) {
     671            1 :         aicpusd_err(
     672              :             "The file is not a regular file or not exist, filePath=%s, exist=%d", filePath.c_str(),
     673              :             static_cast<int32_t>(IsFileExist(filePath)));
     674            1 :         return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     675              :     }
     676              : 
     677            3 :     std::ifstream file(filePath, std::ios::binary | std::ios::ate);
     678            3 :     if (!file.is_open()) {
     679            1 :         aicpusd_err("Open file failed, filePath=%s, reason=%s", filePath.c_str(), strerror(errno));
     680            1 :         return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     681              :     }
     682            4 :     const ScopeGuard fileGuard([&file]() { (void)file.close(); });
     683            2 :     std::streamsize size = file.tellg();
     684            2 :     if (static_cast<uint64_t>(size) > MAX_FILE_SIZE) {
     685            0 :         aicpusd_err("The file size is large than max file size(200MB), size=%luBytes", static_cast<uint64_t>(size));
     686            0 :         return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     687              :     }
     688              : 
     689            2 :     file.seekg(0, std::ios::beg);
     690            2 :     std::vector<char_t> buffer = {};
     691            2 :     buffer.resize(size);
     692            2 :     file.read(&buffer[0], size);
     693              : 
     694            2 :     hashInfo.hashValue = GetQuickHash(buffer.data(), size);
     695            2 :     hashInfo.fileSize = size;
     696            2 :     hashInfo.filePath = filePath;
     697              : 
     698            2 :     return AICPU_SCHEDULE_OK;
     699            3 : }
     700              : 
     701            2 : void HashCalculator::AddHashInfoToCache(const FileHashInfo& hashInfo)
     702              : {
     703            2 :     cache_.emplace_back(hashInfo);
     704            2 :     aicpusd_info(
     705              :         "Add file %s to cache, size=%lu, hash=%lu", hashInfo.filePath.c_str(), hashInfo.fileSize, hashInfo.hashValue);
     706            2 : }
     707              : 
     708            5 : bool HashCalculator::IsFileInCache(const std::string& filePath) const
     709              : {
     710            6 :     for (const auto& hashInfo : cache_) {
     711            4 :         if (filePath == hashInfo.filePath) {
     712            3 :             return true;
     713              :         }
     714              :     }
     715              : 
     716            2 :     return false;
     717              : }
     718              : 
     719           19 : uint64_t HashCalculator::GetQuickHash(const void* data, const size_t size)
     720              : {
     721              :     /*
     722              :      * Using the FNV-1a algorithm for hash computation offers faster speed.
     723              :      * Here, it is solely used to record whether files are consistent and does not involve security scenarios.
     724              :      * In the event of a hash collision, the worst consequence would merely be saving an additional copy of a file.
     725              :      */
     726           19 :     const uint8_t* bytes = static_cast<const uint8_t*>(data);
     727           19 :     const uint64_t prime = 1099511628211UL;
     728           19 :     uint64_t hash = 14695981039346656037UL;
     729              : 
     730           19 :     constexpr size_t parallelNum = 8UL;
     731           19 :     size_t i = 0UL;
     732           46 :     for (; i + parallelNum <= size; i += parallelNum) {
     733           27 :         hash ^= bytes[i];
     734           27 :         hash *= prime;
     735           27 :         hash ^= bytes[i + 1UL];
     736           27 :         hash *= prime;
     737           27 :         hash ^= bytes[i + 2UL];
     738           27 :         hash *= prime;
     739           27 :         hash ^= bytes[i + 3UL];
     740           27 :         hash *= prime;
     741           27 :         hash ^= bytes[i + 4UL];
     742           27 :         hash *= prime;
     743           27 :         hash ^= bytes[i + 5UL];
     744           27 :         hash *= prime;
     745           27 :         hash ^= bytes[i + 6UL];
     746           27 :         hash *= prime;
     747           27 :         hash ^= bytes[i + 7UL];
     748           27 :         hash *= prime;
     749              :     }
     750              : 
     751           62 :     for (; i < size; i++) {
     752           43 :         hash ^= bytes[i];
     753           43 :         hash *= prime;
     754              :     }
     755              : 
     756           19 :     return hash;
     757              : }
     758              : 
     759            8 : int32_t HashCalculator::GetFileNameInDir(std::vector<std::string>& file_names) const
     760              : {
     761            8 :     const std::string dirPath = soRootPath_ + CP_CUSTOM_SO_LIB_NAME;
     762            8 :     DIR* dir = opendir(dirPath.c_str());
     763            8 :     if (dir == nullptr) {
     764            5 :         aicpusd_run_warn("Open dir failed, path=%s, reason=%s", dirPath.c_str(), strerror(errno));
     765            5 :         return AICPU_SCHEDULE_OK;
     766              :     }
     767              : 
     768            3 :     dirent* entry = nullptr;
     769           15 :     while ((entry = readdir(dir)) != nullptr) {
     770            9 :         if (entry->d_type == DT_REG) {
     771            3 :             file_names.emplace_back(entry->d_name);
     772              :         }
     773              :     }
     774              : 
     775            3 :     const int32_t ret = closedir(dir);
     776            3 :     if (ret != 0) {
     777            0 :         aicpusd_warn("Close dir failed, ret=%d, path=%s, reason=%s", ret, dirPath.c_str(), strerror(errno));
     778              :     }
     779              : 
     780            3 :     return AICPU_SCHEDULE_OK;
     781            8 : }
     782              : 
     783            5 : bool HashCalculator::IsFileExist(const std::string& filePath) const
     784              : {
     785            5 :     struct stat st = {};
     786            5 :     return (stat(filePath.c_str(), &st) == 0);
     787              : }
     788              : 
     789            3 : bool HashCalculator::IsRegularFile(const std::string& filePath) const
     790              : {
     791            3 :     struct stat st = {};
     792            3 :     if (stat(filePath.c_str(), &st) != 0) {
     793            0 :         return false;
     794              :     }
     795              : 
     796            3 :     return S_ISREG(st.st_mode);
     797              : }
     798              : 
     799            3 : void CustSoFileLock::InitFileLocker(const std::string& filePath)
     800              : {
     801            3 :     locker_ = open(filePath.c_str(), O_RDONLY);
     802            3 :     if (locker_ < 0) {
     803            3 :         aicpusd_run_warn("Open file locker may not exist, path=%s, reason=%s", filePath.c_str(), strerror(errno));
     804              :     }
     805              : 
     806            3 :     aicpusd_info("Init cust so file locker success, path=%s, fd=%d", filePath.c_str(), locker_);
     807            3 : }
     808              : 
     809            7 : void CustSoFileLock::LockFileLocker() const
     810              : {
     811            7 :     if (locker_ < 0) {
     812            5 :         return;
     813              :     }
     814              : 
     815            2 :     const int32_t ret = flock(locker_, LOCK_EX);
     816            2 :     if (ret != 0) {
     817            1 :         aicpusd_err("Lock write file lock failed, reason=%s", strerror(errno));
     818              :     }
     819              : }
     820              : 
     821            7 : void CustSoFileLock::UnlockFileLocker() const
     822              : {
     823            7 :     if (locker_ < 0) {
     824            5 :         return;
     825              :     }
     826              : 
     827            2 :     const int32_t ret = flock(locker_, LOCK_UN);
     828            2 :     if (ret != 0) {
     829            1 :         aicpusd_err("Unlock file lock failed, reason=%s", strerror(errno));
     830              :     }
     831              : }
     832              : } // namespace AicpuSchedule
        

Generated by: LCOV version 2.0-1