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 : }
|