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: 87.6 % 476 417
Test Date: 2026-07-28 10:54:05 Functions: 97.3 % 37 36

            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 = static_cast<mode_t>(READ_OWNER)  |
      51              :                                 static_cast<mode_t>(WRITE_OWNER) |
      52              :                                 static_cast<mode_t>(READ_GROUP);
      53              :     // permissions to 750
      54              :     constexpr mode_t MODE_750 = static_cast<mode_t>(READ_OWNER)  |
      55              :                                 static_cast<mode_t>(WRITE_OWNER) |
      56              :                                 static_cast<mode_t>(EXEC_OWNER)  |
      57              :                                 static_cast<mode_t>(READ_GROUP)  |
      58              :                                 static_cast<mode_t>(EXEC_GROUP);
      59              : }
      60              : 
      61              : namespace AicpuSchedule {
      62          123 :     AicpuCustSoManager &AicpuCustSoManager::GetInstance()
      63              :     {
      64          123 :         static AicpuCustSoManager instance;
      65          123 :         return instance;
      66              :     }
      67              : 
      68           37 :     int32_t AicpuCustSoManager::InitAicpuCustSoManager(const aicpu::AicpuRunMode mode,
      69              :                                                        const AicpuSchedMode schedMode)
      70              :     {
      71           37 :         runMode_ = mode;
      72           37 :         schedMode_ = schedMode;
      73           37 :         (void)GetDirForCustAicpuSo(custSoRootPath_);
      74              :         // init cust so soft link path
      75           37 :         custSoDirName_ = GetPathForCustAicpuSoftLink();
      76           37 :         if (runMode_ == aicpu::AicpuRunMode::PROCESS_PCIE_MODE) {
      77            3 :             hashCalculator_.SetSoRootPath(custSoRootPath_);
      78            3 :             fileLocker_.InitFileLocker(custSoRootPath_ + CP_CUSTOM_SO_LOCK_NAME);
      79              :         }
      80              : 
      81           37 :         aicpusd_run_info("Cust so manager init successfully, dir=%s, runMode=%u, schedMode=%u.",
      82              :                          custSoDirName_.c_str(), static_cast<uint32_t>(runMode_), static_cast<uint32_t>(schedMode));
      83           37 :         return AICPU_SCHEDULE_OK;
      84              :     }
      85              : 
      86           31 :     bool AicpuCustSoManager::IsSupportCustAicpu() const
      87              :     {
      88              :         // msgq mode does not support cust aicpu
      89           31 :         if (schedMode_ == SCHED_MODE_MSGQ) {
      90            3 :             return false;
      91              :         }
      92           28 :         return true;
      93              :     }
      94              : 
      95           28 :     int32_t AicpuCustSoManager::CheckAndCreateSoFile(const LoadOpFromBufArgs *const args, std::string &soName)
      96              :     {
      97              :         // check init result
      98           28 :         if (!CheckCustSoPath()) {
      99            1 :             return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     100              :         }
     101              : 
     102           27 :         if (args == nullptr) {
     103            1 :             aicpusd_err("cust so ptr is null.");
     104            1 :             return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     105              :         }
     106              :         // check so buf
     107           26 :         char_t *const soBuf = PtrToPtr<void, char_t>(ValueToPtr(args->kernelSoBuf));
     108           26 :         if (soBuf == nullptr) {
     109            1 :             aicpusd_err("BatchLoadOpFromBuf kernel so buf ptr is null.");
     110            1 :             return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     111              :         }
     112              :         // check so buf len
     113           25 :         const uint32_t soBufLen = static_cast<uint32_t>(args->kernelSoBufLen);
     114           25 :         if (soBufLen == 0U) {
     115            3 :             aicpusd_err("BatchLoadOpFromBuf kernel input param soBufLen must > 0");
     116            3 :             return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     117              :         }
     118              :         // check so name
     119           22 :         const char_t * const soNamePtr = static_cast<const char_t *>(ValueToPtr(args->kernelSoName));
     120           22 :         if (soNamePtr == nullptr) {
     121            1 :             aicpusd_err("BatchLoadOpFromBuf kernel so name ptr is null.");
     122            1 :             return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     123              :         }
     124              :         // check so name len
     125           21 :         const uint32_t soNameLen = static_cast<uint32_t>(args->kernelSoNameLen);
     126           21 :         if ((soNameLen == 0U) || (soNameLen > MAX_CUST_SO_NAME_LEN)) {
     127            1 :             aicpusd_err("BatchLoadOpFromBuf kernel input param soNameLen=%u not in (0, %u].",
     128              :                 soNameLen, MAX_CUST_SO_NAME_LEN);
     129            1 :             return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     130              :         }
     131              : 
     132              :         // crate so file
     133           20 :         const std::string realSoName(soNamePtr, static_cast<size_t>(soNameLen));
     134           20 :         const FileInfo fileInfo = {.data=soBuf, .size=soBufLen, .name=realSoName};
     135           20 :         const int32_t ret = CreateSoFile(fileInfo);
     136           20 :         if (ret != AICPU_SCHEDULE_OK) {
     137            3 :             aicpusd_err("Process BatchLoadOpFromBuf failed as parse so file failed, so name[%s].", realSoName.c_str());
     138            3 :             return ret;
     139              :         }
     140           17 :         soName = realSoName;
     141           17 :         return AICPU_SCHEDULE_OK;
     142           20 :     }
     143              : 
     144           18 :     int32_t AicpuCustSoManager::CheckAndDeleteSoFile(const LoadOpFromBufArgs *const args)
     145              :     {
     146              :         // check init result
     147           18 :         if (!CheckCustSoPath()) {
     148            1 :             aicpusd_err("Check cust so path fail");
     149            1 :             return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     150              :         }
     151              : 
     152           17 :         if (args == nullptr) {
     153            1 :             aicpusd_err("cust so ptr is null.");
     154            1 :             return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     155              :         }
     156              :         // check so name len
     157           16 :         const uint32_t soNameLen = static_cast<uint32_t>(args->kernelSoNameLen);
     158           16 :         if ((soNameLen == 0U) || (soNameLen > MAX_CUST_SO_NAME_LEN)) {
     159            2 :             aicpusd_err("LoadOpFromBuf kernel input param soNameLen=%u not in (0, %u].",
     160              :                 soNameLen, MAX_CUST_SO_NAME_LEN);
     161            2 :             return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     162              :         }
     163              :         // check so name
     164           14 :         if (args->kernelSoName == 0U) {
     165            1 :             aicpusd_err("so name ptr is null.");
     166            1 :             return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     167              :         }
     168           13 :         const std::string realSoName(static_cast<const char_t *>(ValueToPtr(args->kernelSoName)),
     169           13 :             static_cast<size_t>(soNameLen));
     170           13 :         if (realSoName.find_first_not_of(CP_PATTERN_FOR_SO_NAME) != std::string::npos) {
     171            1 :             aicpusd_err("Cust so name %s is not invalid. Please check!", realSoName.c_str());
     172            1 :             return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     173              :         }
     174              : 
     175           12 :         std::string fileName;
     176           12 :         (void) fileName.append(custSoDirName_).append(std::string(realSoName));
     177           12 :         if (access(fileName.c_str(), F_OK) != 0) {
     178            9 :             aicpusd_run_warn(
     179              :                 "Check deleteCustOp's so full path:%s failed, error:%s", fileName.c_str(), strerror(errno));
     180            9 :             return AICPU_SCHEDULE_OK;
     181              :         }
     182              :         // check so file
     183            3 :         const int32_t ret = CheckSoFullPathValid(fileName);
     184            3 :         if (ret != AICPU_SCHEDULE_OK) {
     185            1 :             return ret;
     186              :         }
     187              : 
     188              :         // delete so
     189            2 :         return DeleteSoFile(custSoDirName_, fileName);
     190           13 :     }
     191              : 
     192            7 :     int32_t AicpuCustSoManager::CheckAndDeleteCustSoDir()
     193              :     {
     194              :         // check init result
     195            7 :         if (!CheckCustSoPath()) {
     196            1 :             return AICPU_SCHEDULE_OK;
     197              :         }
     198              : 
     199            6 :         const std::string dirName(custSoDirName_);
     200              :         // check whether dir is empty. If empty, delete dir
     201              :         {
     202            6 :             const std::lock_guard<std::mutex> soFileLock(soFileMutex_);
     203            6 :             if (CheckDirEmpty(dirName)) {
     204            2 :                 if (remove(dirName.c_str()) != 0) {
     205            1 :                     aicpusd_run_info("Delete dir:%s failed, error is %s.", dirName.c_str(), strerror(errno));
     206              :                 } else {
     207            1 :                     aicpusd_info("Delete dir:%s success.", dirName.c_str());
     208              :                 }
     209              :             }
     210            6 :         }
     211            6 :         return AICPU_SCHEDULE_OK;
     212            6 :     }
     213              : 
     214           14 :     int32_t AicpuCustSoManager::CreateSoFile(const FileInfo &fileInfo)
     215              :     {
     216           14 :         aicpusd_info("begin to create so file. soName is %s", fileInfo.name.c_str());
     217              :         // check so name
     218           14 :         const std::string kernelSo(fileInfo.name);
     219           14 :         if (kernelSo.find_first_not_of(CP_PATTERN_FOR_SO_NAME) != std::string::npos) {
     220            1 :             aicpusd_err("Cust so name %s is not invalid. Please check!", kernelSo.c_str());
     221            1 :             return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
     222              :         }
     223              : 
     224           13 :         const int32_t ret = DoCreateSoFile(fileInfo);
     225           13 :         if (ret != AICPU_SCHEDULE_OK) {
     226            4 :             aicpusd_err("Create so failed, path=%s", fileInfo.name.c_str());
     227            4 :             return ret;
     228              :         }
     229              : 
     230              :         // load so if current aicpu mode is thread mode(minirc/ctrlcpu/lhisi)
     231            9 :         if (runMode_ == aicpu::AicpuRunMode::THREAD_MODE) {
     232            7 :             const uint32_t loadSoNum = 1U;
     233            7 :             const char *soNames[loadSoNum] = {fileInfo.name.c_str()};
     234            7 :             (void)aeBatchLoadKernelSo(aicpu::KERNEL_TYPE_AICPU_CUSTOM, loadSoNum, &(soNames[0]));
     235              :         }
     236            9 :         aicpusd_info("Create so file %s success", fileInfo.name.c_str());
     237            9 :         return AICPU_SCHEDULE_OK;
     238           14 :     }
     239              : 
     240           13 :     int32_t AicpuCustSoManager::DoCreateSoFile(const FileInfo &fileInfo)
     241              :     {
     242           13 :         const std::lock_guard<std::mutex> soFileLock(soFileMutex_);
     243           13 :         const std::string softLinkPath = custSoDirName_ + fileInfo.name;
     244           13 :         if (runMode_ != aicpu::AicpuRunMode::PROCESS_PCIE_MODE) {
     245            8 :             aicpusd_info("Aicpu is not process mode, only write file. path=%s", softLinkPath.c_str());
     246            8 :             const FileInfo newFileInfo = {.data=fileInfo.data, .size=fileInfo.size, .name=softLinkPath};
     247            8 :             return WriteBufToSoFile(newFileInfo, GetPathForCustAicpuSoftLink());
     248            8 :         }
     249              : 
     250            5 :         int32_t ret = AICPU_SCHEDULE_OK;
     251            5 :         FileHashInfo existedFileInfo = {};
     252            5 :         const std::string soFullPath = GenerateSoFullPath(fileInfo.name); // The real so name, not is soft link
     253            5 :         const FileInfo newFileInfo = {.data=fileInfo.data, .size=fileInfo.size, .name=soFullPath};
     254            5 :         fileLocker_.LockFileLocker();
     255            5 :         if (hashCalculator_.GetSameFileInfo(newFileInfo, existedFileInfo)) {
     256            4 :             ret = CreateSoftLinkToSoFile(softLinkPath, existedFileInfo.filePath);
     257              :         } else {
     258            1 :             ret = WriteBufToSoFile(newFileInfo, GetPathForCustAicpuRealSo());
     259            1 :             if (ret == AICPU_SCHEDULE_OK) {
     260            0 :                 ret = CreateSoftLinkToSoFile(softLinkPath, soFullPath);
     261              :             }
     262              :         }
     263            5 :         fileLocker_.UnlockFileLocker();
     264            5 :         if (ret != AICPU_SCHEDULE_OK) {
     265            3 :             aicpusd_err("Create so file failed, so=%s", softLinkPath.c_str());
     266            3 :             return ret;
     267              :         }
     268              : 
     269            2 :         return ret;
     270           13 :     }
     271              : 
     272           13 :     int32_t AicpuCustSoManager::WriteBufToSoFile(const FileInfo &fileInfo, const std::string &dirPath) const
     273              :     {
     274           13 :         const std::string soName = fileInfo.name;
     275              :         // check and make dir
     276           13 :         int32_t ret = CheckOrMakeDirectory(dirPath);
     277           13 :         if (ret != 0) {
     278            0 :             aicpusd_err("Check or create directory:%s failed.", dirPath.c_str());
     279            0 :             return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     280              :         }
     281              :         // serious security problem, must check realpath
     282           13 :         ret = CheckSoFullPathValid(soName);
     283           13 :         if (ret != AICPU_SCHEDULE_OK) {
     284            3 :             return ret;
     285              :         }
     286              :         // check whether so exist
     287           10 :         if (access(soName.c_str(), F_OK) == 0) {
     288            1 :             aicpusd_info("%s already exists in the current directory, no need to write again.", soName.c_str());
     289            1 :             return AICPU_SCHEDULE_OK;
     290              :         }
     291              :         try {
     292            9 :             std::ofstream soFile(soName, std::ios::out | std::ios::binary);
     293            9 :             if (!soFile) {
     294            1 :                 aicpusd_err("Fail to open file:%s. reason=%s", soName.c_str(), strerror(errno));
     295            1 :                 return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     296              :             }
     297           16 :             const ScopeGuard fileGuard([&soFile] () { soFile.close(); });
     298            8 :             (void) soFile.write(fileInfo.data, static_cast<std::streamsize>(fileInfo.size));
     299            8 :             if (!soFile.good()) {
     300            0 :                 aicpusd_err("Fail to write file:%s, length:%u, eof=%d, bad=%d, fail=%d, reason=%s. please check host so size",
     301              :                             soName.c_str(), fileInfo.size, soFile.eof(), soFile.bad(), soFile.fail(), strerror(errno));
     302            0 :                 return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     303              :             }
     304            8 :             soFile.flush();
     305            8 :             if (!soFile.good()) {
     306            1 :                 aicpusd_err("Fail to flush file:%s, length:%u, eof=%d, bad=%d, fail=%d, reason=%s. please check host so size",
     307              :                             soName.c_str(), fileInfo.size, soFile.eof(), soFile.bad(), soFile.fail(), strerror(errno));
     308            1 :                 return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     309              :             }
     310           10 :         } catch (const std::ofstream::failure &err) {
     311            0 :             aicpusd_err("Fail to write file:%s, err=%s, reason=%s.", soName.c_str(), err.what(), strerror(errno));
     312            0 :             return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     313            0 :         }
     314              :         // change so file permissions to 640
     315            7 :         if (chmod(soName.c_str(), MODE_640) != 0) {
     316            0 :             aicpusd_err("Change file:%s mode failed.", soName.c_str());
     317            0 :             return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     318              :         }
     319            7 :         const uint64_t hashValue = HashCalculator::GetQuickHash(fileInfo.data, fileInfo.size);
     320            7 :         aicpusd_run_info("Write buffer to so success, path=%s, hash=%llu, fileSize=%zu", soName.c_str(), hashValue, fileInfo.size);
     321            7 :         return AICPU_SCHEDULE_OK;
     322           13 :     }
     323              : 
     324            4 :     int32_t AicpuCustSoManager::CreateSoftLinkToSoFile(const std::string &softLinkPath, const std::string &existedSoPath)
     325              :     {
     326            4 :         if (access(existedSoPath.c_str(), F_OK) != 0) {
     327            1 :             aicpusd_err("The target path is not existed in device, cannot create. linkPath=%s, targetPath=%s",
     328              :                         softLinkPath.c_str(), existedSoPath.c_str());
     329            1 :             return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     330              :         }
     331              : 
     332            3 :         if (access(softLinkPath.c_str(), F_OK) == 0) {
     333            1 :             aicpusd_info("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",
     347              :                         softLinkPath.c_str(), existedSoPath.c_str());
     348            0 :             return ret;
     349              :         }
     350              : 
     351            1 :         ret = symlink(existedSoPath.c_str(), softLinkPath.c_str());
     352            1 :         if (ret != 0) {
     353            0 :             aicpusd_err("Create soft links failed, ret=%d, linkPath=%s, targetPath=%s, reason=%s",
     354              :                         ret, softLinkPath.c_str(), existedSoPath.c_str(), strerror(errno));
     355            0 :             return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     356              :         }
     357              : 
     358            1 :         aicpusd_run_info("Create soft link so success, linkPath=%s, targetPath=%s",
     359              :                          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
     422              :     {
     423            6 :         return custSoRootPath_ + CP_CUSTOM_SO_LIB_NAME;
     424              :     }
     425              : 
     426           45 :     std::string AicpuCustSoManager::GetPathForCustAicpuSoftLink() const
     427              :     {
     428           45 :         const uint32_t uniqueVfId = AicpuDrvManager::GetInstance().GetUniqueVfId();
     429           45 :         std::string dirName = custSoRootPath_;
     430           45 :         const uint32_t deviceId = AicpuDrvManager::GetInstance().GetDeviceId();
     431           45 :         const pid_t hostPid = AicpuDrvManager::GetInstance().GetHostPid();
     432           45 :         (void) dirName.append(CP_CUSTOM_SO_DIR_NAME_PREFIX)
     433           45 :             .append(std::to_string(deviceId)).append("_")
     434           90 :             .append(std::to_string(uniqueVfId)).append("_")
     435           45 :             .append(std::to_string(static_cast<int32_t>(hostPid))).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("Accessing cust so dir %s was not successful, reason is %s.",
     547              :                              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) + "." +
     607           15 :                std::to_string(uniqueVfId) + "." + std::to_string(hostPid);
     608              :     }
     609              : 
     610            5 :     bool HashCalculator::GetSameFileInfo(const FileInfo &fileInfo, FileHashInfo &existedFileHashInfo) {
     611            5 :         UpdateCache();
     612              : 
     613            5 :         const uint64_t hashValue = GetQuickHash(fileInfo.data, fileInfo.size);
     614            5 :         if (GetSameHashFileFromCache(hashValue, existedFileHashInfo)) {
     615            4 :             aicpusd_info("The file has same existed file after hash compare, so=%s, hash=%lu",
     616              :                          fileInfo.name.c_str(), hashValue);
     617            4 :             return true;
     618              :         }
     619              : 
     620            1 :         FileHashInfo hashInfo = {};
     621            1 :         hashInfo.filePath = fileInfo.name;
     622            1 :         hashInfo.fileSize = fileInfo.size;
     623            1 :         hashInfo.hashValue = hashValue;
     624            1 :         AddHashInfoToCache(hashInfo);
     625              : 
     626            1 :         return false;
     627            1 :     }
     628              : 
     629            5 :     void HashCalculator::UpdateCache()
     630              :     {
     631            5 :         std::vector<std::string> file_names = {};
     632            5 :         int32_t ret = GetFileNameInDir(file_names);
     633            5 :         if (ret != AICPU_SCHEDULE_OK) {
     634            0 :             aicpusd_warn("Get file name in dir failed");
     635            0 :             return;
     636              :         }
     637              : 
     638            5 :         for (const auto &file_name : file_names) {
     639            0 :             const std::string filePath = soRootPath_ + CP_CUSTOM_SO_LIB_NAME + file_name;
     640            0 :             if (IsFileInCache(filePath)) {
     641            0 :                 continue;
     642              :             }
     643              : 
     644            0 :             aicpusd_info("Start to read so %s", filePath.c_str());
     645            0 :             FileHashInfo hashInfo = {};
     646            0 :             ret = GenerateFileHashInfo(filePath, hashInfo);
     647            0 :             if (ret != AICPU_SCHEDULE_OK) {
     648            0 :                 aicpusd_err("Get file hash info failed, filePath=%s", filePath.c_str());
     649              :             } else {
     650            0 :                 AddHashInfoToCache(hashInfo);
     651              :             }
     652            0 :         }
     653            5 :     }
     654              : 
     655            5 :     bool HashCalculator::GetSameHashFileFromCache(const uint64_t hashValue, FileHashInfo &existedFileHashInfo) const
     656              :     {
     657            5 :         for (const auto &hashInfo : cache_) {
     658            4 :             if (hashValue == hashInfo.hashValue) {
     659            4 :                 existedFileHashInfo = hashInfo;
     660            4 :                 return true;
     661              :             }
     662              :         }
     663              : 
     664            1 :         return false;
     665              :     }
     666              : 
     667            2 :     int32_t HashCalculator::GenerateFileHashInfo(const std::string &filePath, FileHashInfo &hashInfo) const
     668              :     {
     669            2 :         if (!IsFileExist(filePath) || !IsRegularFile(filePath)) {
     670            1 :             aicpusd_err("The file is not a regular file or not exist, filePath=%s, exist=%d",
     671              :                         filePath.c_str(), static_cast<int32_t>(IsFileExist(filePath)));
     672            1 :             return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     673              :         }
     674              : 
     675            1 :         std::ifstream file(filePath, std::ios::binary | std::ios::ate);
     676            1 :         if (!file.is_open()) {
     677            1 :             aicpusd_err("Open file failed, filePath=%s, reason=%s", filePath.c_str(), strerror(errno));
     678            1 :             return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     679              :         }
     680            0 :         const ScopeGuard fileGuard([&file]() { (void)file.close(); });
     681            0 :         std::streamsize size = file.tellg();
     682            0 :         if (static_cast<uint64_t>(size) > MAX_FILE_SIZE) {
     683            0 :             aicpusd_err("The file size is large than max file size(200MB), size=%luBytes", static_cast<uint64_t>(size));
     684            0 :             return AICPU_SCHEDULE_ERROR_INNER_ERROR;
     685              :         }
     686              : 
     687            0 :         file.seekg(0, std::ios::beg);
     688            0 :         std::vector<char_t> buffer = {};
     689            0 :         buffer.resize(size);
     690            0 :         file.read(&buffer[0], size);
     691              : 
     692            0 :         hashInfo.hashValue = GetQuickHash(buffer.data(), size);
     693            0 :         hashInfo.fileSize = size;
     694            0 :         hashInfo.filePath = filePath;
     695              : 
     696            0 :         return AICPU_SCHEDULE_OK;
     697            1 :     }
     698              : 
     699            1 :     void HashCalculator::AddHashInfoToCache(const FileHashInfo &hashInfo)
     700              :     {
     701            1 :         cache_.emplace_back(hashInfo);
     702            1 :         aicpusd_info("Add file %s to cache, size=%lu, hash=%lu", hashInfo.filePath.c_str(),
     703              :                      hashInfo.fileSize, hashInfo.hashValue);
     704            1 :     }
     705              : 
     706            2 :     bool HashCalculator::IsFileInCache(const std::string &filePath) const
     707              :     {
     708            3 :         for (const auto &hashInfo : cache_) {
     709            2 :             if (filePath == hashInfo.filePath) {
     710            1 :                 return true;
     711              :             }
     712              :         }
     713              : 
     714            1 :         return false;
     715              :     }
     716              : 
     717           17 :     uint64_t HashCalculator::GetQuickHash(const void *data, const size_t size)
     718              :     {
     719              :         /*
     720              :         * Using the FNV-1a algorithm for hash computation offers faster speed.
     721              :         * Here, it is solely used to record whether files are consistent and does not involve security scenarios.
     722              :         * In the event of a hash collision, the worst consequence would merely be saving an additional copy of a file.
     723              :         */
     724           17 :         const uint8_t* bytes = static_cast<const uint8_t*>(data);
     725           17 :         const uint64_t prime = 1099511628211UL;
     726           17 :         uint64_t hash = 14695981039346656037UL;
     727              : 
     728           17 :         constexpr size_t parallelNum = 8UL;
     729           17 :         size_t i = 0UL;
     730           42 :         for (; i + parallelNum <= size; i += parallelNum) {
     731           25 :             hash ^= bytes[i];
     732           25 :             hash *= prime;
     733           25 :             hash ^= bytes[i + 1UL];
     734           25 :             hash *= prime;
     735           25 :             hash ^= bytes[i + 2UL];
     736           25 :             hash *= prime;
     737           25 :             hash ^= bytes[i + 3UL];
     738           25 :             hash *= prime;
     739           25 :             hash ^= bytes[i + 4UL];
     740           25 :             hash *= prime;
     741           25 :             hash ^= bytes[i + 5UL];
     742           25 :             hash *= prime;
     743           25 :             hash ^= bytes[i + 6UL];
     744           25 :             hash *= prime;
     745           25 :             hash ^= bytes[i + 7UL];
     746           25 :             hash *= prime;
     747              :         }
     748              : 
     749           57 :         for (; i < size; i++) {
     750           40 :             hash ^= bytes[i];
     751           40 :             hash *= prime;
     752              :         }
     753              : 
     754           17 :         return hash;
     755              :     }
     756              : 
     757            5 :     int32_t HashCalculator::GetFileNameInDir(std::vector<std::string> &file_names) const
     758              :     {
     759            5 :         const std::string dirPath = soRootPath_ + CP_CUSTOM_SO_LIB_NAME;
     760            5 :         DIR *dir = opendir(dirPath.c_str());
     761            5 :         if (dir == nullptr) {
     762            5 :             aicpusd_run_warn("Open dir failed, path=%s, reason=%s", dirPath.c_str(), strerror(errno));
     763            5 :             return AICPU_SCHEDULE_OK;
     764              :         }
     765              : 
     766            0 :         dirent *entry = nullptr;
     767            0 :         while ((entry = readdir(dir)) != nullptr)
     768              :         {
     769            0 :             if (entry->d_type == DT_REG) {
     770            0 :                 file_names.emplace_back(entry->d_name);
     771              :             }
     772              :         }
     773              : 
     774            0 :         const int32_t ret = closedir(dir);
     775            0 :         if (ret != 0) {
     776            0 :             aicpusd_warn("Close dir failed, ret=%d, path=%s, reason=%s", ret, dirPath.c_str(), strerror(errno));
     777              :         }
     778              : 
     779            0 :         return AICPU_SCHEDULE_OK;
     780            5 :     }
     781              : 
     782            3 :     bool HashCalculator::IsFileExist(const std::string &filePath) const
     783              :     {
     784            3 :         struct stat st = {};
     785            3 :         return (stat(filePath.c_str(), &st) == 0);
     786              :     }
     787              : 
     788            1 :     bool HashCalculator::IsRegularFile(const std::string &filePath) const
     789              :     {
     790            1 :         struct stat st = {};
     791            1 :         if (stat(filePath.c_str(), &st) != 0) {
     792            0 :             return false;
     793              :         }
     794              : 
     795            1 :         return S_ISREG(st.st_mode);
     796              :     }
     797              : 
     798            3 :     void CustSoFileLock::InitFileLocker(const std::string &filePath)
     799              :     {
     800            3 :         locker_ = open(filePath.c_str(), O_RDONLY);
     801            3 :         if (locker_ < 0) {
     802            3 :             aicpusd_run_warn("Open file locker may not exist, path=%s, reason=%s", filePath.c_str(), strerror(errno));
     803              :         }
     804              : 
     805            3 :         aicpusd_info("Init cust so file locker success, path=%s, fd=%d", filePath.c_str(), locker_);
     806            3 :     }
     807              : 
     808            7 :     void CustSoFileLock::LockFileLocker() const
     809              :     {
     810            7 :         if (locker_ < 0) {
     811            5 :             return;
     812              :         }
     813              : 
     814            2 :         const int32_t ret = flock(locker_, LOCK_EX);
     815            2 :         if (ret != 0) {
     816            1 :             aicpusd_err("Lock write file lock failed, reason=%s", strerror(errno));
     817              :         }
     818              :     }
     819              : 
     820            7 :     void CustSoFileLock::UnlockFileLocker() const
     821              :     {
     822            7 :         if (locker_ < 0) {
     823            5 :             return;
     824              :         }
     825              : 
     826            2 :         const int32_t ret = flock(locker_, LOCK_UN);
     827            2 :         if (ret != 0) {
     828            1 :             aicpusd_err("Unlock file lock failed, reason=%s", strerror(errno));
     829              :         }
     830              :     }
     831              : }
        

Generated by: LCOV version 2.0-1