1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 * Description: offline log file saved to the storage
15 */
16
17 #include "log_file.h"
18 #include <unistd.h>
19 #include <stdlib.h>
20 #include "uapi_crc.h"
21 #include "errcode.h"
22 #include "securec.h"
23 #include "stdbool.h"
24 #include "soc_osal.h"
25 #include "common_def.h"
26 #include "dfx_adapt_layer.h"
27 #include "debug_print.h"
28 #include "log_file_common.h"
29 #include "log_file_file.h"
30 #include "log_file_flash.h"
31
32 #if (CONFIG_DFX_SUPPORT_OFFLINE_LOG_FILE == YES)
33
34 STATIC store_file_manage_t g_logfile_manage = { 0 };
35 STATIC osal_mutex g_instance_mutex = {NULL}; /* 实例互斥锁 */
36
logfile_get_manage(void)37 store_file_manage_t* logfile_get_manage(void)
38 {
39 return &g_logfile_manage;
40 }
41
logfile_check_record_head_valid(store_record_info_t * record_header)42 bool logfile_check_record_head_valid(store_record_info_t *record_header)
43 {
44 if (record_header->magic == RECORD_HEAD_MAGIC) {
45 uint16_t crc = uapi_crc16(0, (uint8_t *)record_header, sizeof(store_record_info_t) - sizeof(uint16_t));
46 if (crc == record_header->crc) {
47 return true;
48 }
49 }
50 return false;
51 }
52
logfile_init_file_head(store_file_info_t * file_info)53 void logfile_init_file_head(store_file_info_t *file_info)
54 {
55 #if defined(CONFIG_DFX_SUPPORT_FILE_SYSTEM) && (CONFIG_DFX_SUPPORT_FILE_SYSTEM == DFX_NO)
56 file_info->file_head.version = 2; // flash存储version值为2
57 #else
58 file_info->file_head.version = 1; // 文件存储version值为1
59 #endif
60 file_info->file_head.cur_pos = (uint32_t)sizeof(file_info->file_head);
61 file_info->file_head.file_size = file_info->file_cfg.file_size;
62 file_info->file_head.first_record_pos = (uint32_t)sizeof(file_info->file_head);
63 file_info->file_head.offset = (uint8_t)sizeof(file_info->file_head);
64 file_info->file_head.start_flag = FILE_HEAD_START_FLAG;
65 file_info->file_head.records = 0;
66 file_info->file_head.service_type = file_info->type;
67 file_info->file_head.crc =
68 uapi_crc16(0, (uint8_t *)&(file_info->file_head), sizeof(store_file_head_t) - sizeof(uint16_t));
69 }
70
logfile_write_to_cache(store_file_info_t * file_info,uint8_t * data,uint32_t data_len)71 STATIC errcode_t logfile_write_to_cache(store_file_info_t *file_info, uint8_t *data, uint32_t data_len)
72 {
73 store_cache_t *cache = file_info->cache;
74 int32_t tmp_pos = 0;
75
76 tmp_pos = (int32_t)cache->cache_read_pos;
77 uint32_t record_len_written = cache->cache_size - cache->cache_write_pos;
78 /* 判断数据是否需要翻转至cache头存储 */
79 if (record_len_written >= data_len) {
80 if (memcpy_s(&(cache->data[cache->cache_write_pos]), record_len_written, data, data_len) != EOK) {
81 return ERRCODE_FAIL;
82 }
83 cache->cache_write_pos += data_len;
84 } else {
85 uint32_t record_len_remained = data_len - record_len_written;
86 if (record_len_written != 0 &&
87 memcpy_s(&(cache->data[cache->cache_write_pos]), record_len_written, data, record_len_written) != EOK) {
88 return ERRCODE_FAIL;
89 }
90 cache->cache_write_pos = 0;
91
92 if (record_len_remained != 0 &&
93 memcpy_s(&(cache->data[cache->cache_write_pos]), (uint32_t)tmp_pos, data + record_len_written,
94 record_len_remained) != EOK) {
95 return ERRCODE_FAIL;
96 }
97 cache->cache_write_pos += record_len_remained;
98 }
99
100 return ERRCODE_SUCC;
101 }
102
logfile_save_process(void * arg)103 STATIC int logfile_save_process(void *arg)
104 {
105 int32_t ret = 0;
106 store_file_manage_t *manage = (store_file_manage_t *)arg;
107 while (true) {
108 for (int i = 0; i < (int)(sizeof(manage->file_info) / sizeof(manage->file_info[0])); i++) {
109 manage->file_info[i].finish_flag = true;
110 }
111
112 ret = osal_event_read(&(manage->event), LOGFILE_SAVE_EVENT_MASK, OSAL_WAIT_FOREVER,
113 OSAL_WAITMODE_OR | OSAL_WAITMODE_CLR);
114
115 for (int i = 0; i < (int)(sizeof(manage->file_info) / sizeof(manage->file_info[0])); i++) {
116 if ((((uint32_t)ret & (1 << (uint32_t)i)) == (uint32_t)(1 << (uint32_t)i)) &&
117 (manage->file_info[i].run_flag == true)) {
118 manage->file_info[i].finish_flag = false;
119 #if defined(CONFIG_DFX_SUPPORT_FILE_SYSTEM) && (CONFIG_DFX_SUPPORT_FILE_SYSTEM == DFX_NO)
120 logfile_write_cache_to_flash(&manage->file_info[i]);
121 #else
122 logfile_write_cache_to_file(&manage->file_info[i]);
123 #endif
124 }
125 }
126 }
127
128 return 0;
129 }
130
logfile_timer_handler(unsigned long data)131 STATIC void logfile_timer_handler(unsigned long data)
132 {
133 unused(data);
134 osal_timer *timer = &(g_logfile_manage.timer_handle);
135
136 for (int i = 0; i < (int)(sizeof(g_logfile_manage.file_info) / sizeof(g_logfile_manage.file_info[0]) - 1); i++) {
137 if (g_logfile_manage.file_info[i].cache != NULL) {
138 osal_event_write(&(g_logfile_manage.event), 1 << (uint32_t)i);
139 }
140 }
141
142 osal_timer_start(timer);
143 }
144
logfile_timer_stop(void)145 STATIC void logfile_timer_stop(void)
146 {
147 osal_timer *timer = &(g_logfile_manage.timer_handle);
148 osal_timer_stop(timer);
149 }
150
logfile_timer_init(void)151 STATIC errcode_t logfile_timer_init(void)
152 {
153 osal_timer *timer = &(g_logfile_manage.timer_handle);
154 timer->handler = logfile_timer_handler;
155 timer->data = 0;
156
157 timer->interval = LOGFILE_TIMER_PERIOD;
158 if (osal_timer_init(timer) < 0) {
159 return ERRCODE_FAIL;
160 }
161 osal_timer_start(timer);
162 return ERRCODE_SUCC;
163 }
164
logfile_create_thread(void)165 STATIC errcode_t logfile_create_thread(void)
166 {
167 errcode_t ret = ERRCODE_DFX_LOGFILE_EVENT_FAILURE;
168 if (g_logfile_manage.task_handle != NULL) {
169 return ERRCODE_SUCC;
170 }
171
172 if ((osal_event_init(&g_logfile_manage.event)) != OSAL_SUCCESS) {
173 goto err1;
174 }
175 ret = ERRCODE_DFX_LOGFILE_MUTEX_FAILURE;
176 if (osal_mutex_init(&g_logfile_manage.file_write_mutex) != OSAL_SUCCESS) {
177 goto err2;
178 }
179
180 osal_kthread_lock();
181 g_logfile_manage.task_handle = osal_kthread_create(logfile_save_process,
182 &g_logfile_manage, "log_save", LOGFILE_SAVE_TASK_SIZE);
183
184 if (g_logfile_manage.task_handle == NULL) {
185 ret = ERRCODE_DFX_LOGFILE_THREAD_FAILURE;
186 osal_kthread_unlock();
187 goto err3;
188 }
189 osal_kthread_set_priority(g_logfile_manage.task_handle, THREAD_PRIORITY_NUM);
190 osal_kthread_unlock();
191
192 if (logfile_timer_init() != OSAL_SUCCESS) {
193 ret = ERRCODE_DFX_LOGFILE_TIMER_FAILURE;
194 goto err4;
195 }
196 return ERRCODE_SUCC;
197 err4:
198 if (g_logfile_manage.task_handle != NULL) {
199 osal_kthread_destroy(g_logfile_manage.task_handle, 0);
200 }
201 err3:
202 osal_mutex_destroy(&g_logfile_manage.file_write_mutex);
203 err2:
204 (void)osal_event_destroy(&g_logfile_manage.event);
205 err1:
206 (void)memset_s(&g_logfile_manage, (sizeof(g_logfile_manage) - sizeof(store_file_info_t) * STORE_MAX),
207 0, (sizeof(g_logfile_manage) - sizeof(store_file_info_t) * STORE_MAX));
208 dfx_log_err("logfile_create_thread failed. ret = 0x%x\r\n", ret);
209 return ret;
210 }
211
logfile_create_cache(store_file_info_t * file_info,store_file_cfg_t * cfg)212 STATIC errcode_t logfile_create_cache(store_file_info_t *file_info, store_file_cfg_t *cfg)
213 {
214 if (file_info->cache == NULL) {
215 file_info->cache = (store_cache_t *)osal_kzalloc_align(sizeof(store_cache_t) + cfg->cache_size,
216 OSAL_GFP_ZERO, 4); /* align 4 bytes */
217 if (file_info->cache == NULL) {
218 dfx_log_err("cache space create failed!\r\n");
219 return ERRCODE_MALLOC;
220 }
221 file_info->cache->cache_size = cfg->cache_size;
222 file_info->cache->threshold_size = cfg->cache_size * 1 / 4; /* threshold size is 1/4 of cache size */
223 }
224
225 return ERRCODE_SUCC;
226 }
227
logfile_file_write_with_cache(store_file_info_t * file_info,uint8_t * data,uint32_t data_len)228 STATIC errcode_t logfile_file_write_with_cache(store_file_info_t *file_info, uint8_t *data, uint32_t data_len)
229 {
230 store_cache_t *cache = file_info->cache;
231 int32_t cache_space_left;
232
233 if (cache != NULL) {
234 store_record_info_t record_info;
235 record_info.magic = RECORD_HEAD_MAGIC;
236 record_info.type = file_info->file_head.service_type;
237 record_info.len = (uint16_t)sizeof(store_record_info_t) + (uint16_t)data_len;
238 record_info.rev = 1;
239 #if defined(CONFIG_DFX_SUPPORT_FILE_SYSTEM) && CONFIG_DFX_SUPPORT_FILE_SYSTEM == DFX_NO
240 if (file_info->file_cfg.mult_files != 1 || file_info->file_cfg.cache_size <= 0) {
241 return ERRCODE_INVALID_PARAM;
242 }
243 record_info.index = (uint16_t)(file_info->index);
244 file_info->index = (file_info->index == MAX_INDEX_NUM) ? 1 : (file_info->index + 1);
245 #endif
246 record_info.crc = uapi_crc16(0, (uint8_t *)&record_info, sizeof(store_record_info_t) - sizeof(uint16_t));
247
248 if (cache->cache_read_pos > cache->cache_write_pos) {
249 cache_space_left = (int32_t)(cache->cache_read_pos - cache->cache_write_pos);
250 } else {
251 cache_space_left = (int32_t)(cache->cache_size - cache->cache_write_pos + cache->cache_read_pos);
252 }
253
254 /* 如果cache空间不足,先把当前cache中数据全部写入flash或file */
255 if (cache_space_left <= (int32_t)record_info.len) {
256 #if defined(CONFIG_DFX_SUPPORT_FILE_SYSTEM) && (CONFIG_DFX_SUPPORT_FILE_SYSTEM == DFX_NO)
257 logfile_write_cache_to_flash(file_info);
258 #else
259 logfile_write_cache_to_file(file_info);
260 #endif
261 }
262
263 logfile_write_to_cache(file_info, (uint8_t *)&record_info, (uint32_t)sizeof(store_record_info_t));
264
265 logfile_write_to_cache(file_info, data, data_len);
266
267 if (cache_space_left < (int32_t)cache->threshold_size) {
268 /* cache剩余空间小于门限时,触发保存 */
269 osal_event_write(&(g_logfile_manage.event), 1 << (uint32_t)file_info->type);
270 }
271 }
272
273 return ERRCODE_SUCC;
274 }
275
logfile_free_file_info(store_file_info_t * file_info)276 STATIC void logfile_free_file_info(store_file_info_t *file_info)
277 {
278 #if defined(CONFIG_DFX_SUPPORT_FILE_SYSTEM) && (CONFIG_DFX_SUPPORT_FILE_SYSTEM == DFX_YES)
279 if (file_info->idx_fd != 0) {
280 close(file_info->idx_fd);
281 file_info->idx_fd = 0;
282 }
283
284 if (file_info->fd != 0) {
285 close(file_info->fd);
286 file_info->fd = 0;
287 }
288 #else
289 file_info->fd = 0;
290 #endif
291
292 if (file_info->cache != NULL) {
293 osal_kfree(file_info->cache);
294 file_info->cache = NULL;
295 }
296
297 (void)memset_s(file_info, sizeof(store_file_info_t), 0, sizeof(store_file_info_t));
298 }
299
logfile_free_os_resouce(void)300 STATIC void logfile_free_os_resouce(void)
301 {
302 if (g_logfile_manage.task_handle != NULL) {
303 logfile_timer_stop();
304 (void)osal_timer_destroy(&g_logfile_manage.timer_handle);
305 osal_kthread_destroy(g_logfile_manage.task_handle, 0);
306
307 (void)osal_event_destroy(&g_logfile_manage.event);
308 osal_mutex_destroy(&g_logfile_manage.file_write_mutex);
309
310 (void)memset_s(&g_logfile_manage, (sizeof(g_logfile_manage) - sizeof(store_file_info_t) * STORE_MAX),
311 0, (sizeof(g_logfile_manage) - sizeof(store_file_info_t) * STORE_MAX));
312 }
313 }
314
logfile_write(store_file_info_t * file_info,uint8_t * data,uint32_t data_len)315 STATIC errcode_t logfile_write(store_file_info_t *file_info, uint8_t *data, uint32_t data_len)
316 {
317 errcode_t ret = ERRCODE_SUCC;
318 if (file_info->file_cfg.mult_files < 1) {
319 return ERRCODE_INVALID_PARAM;
320 }
321
322 if (file_info->run_flag == false) {
323 return ERRCODE_DFX_LOGFILE_SUSPENDED;
324 }
325
326 if (file_info->file_cfg.enable_cache == 0) {
327 #if defined(CONFIG_DFX_SUPPORT_FILE_SYSTEM) && (CONFIG_DFX_SUPPORT_FILE_SYSTEM == DFX_YES)
328 if (file_info->file_cfg.mult_files <= 1) {
329 ret = logfile_single_file_write(file_info, data, data_len);
330 } else {
331 ret = logfile_multi_file_write(file_info, data, data_len);
332 }
333 #endif
334 } else {
335 ret = logfile_file_write_with_cache(file_info, data, data_len);
336 }
337 return ret;
338 }
339
uapi_logfile_write(store_service_t service_type,uint8_t sub_type,uint8_t * data,uint32_t data_len)340 errcode_t uapi_logfile_write(store_service_t service_type, uint8_t sub_type, uint8_t *data, uint32_t data_len)
341 {
342 errcode_t ret;
343
344 unused(sub_type);
345 if (service_type >= STORE_MAX || data == NULL || data_len == 0) {
346 return ERRCODE_INVALID_PARAM;
347 }
348
349 store_file_info_t *file_info = &(g_logfile_manage.file_info[service_type]);
350 osal_mutex_lock(&g_instance_mutex);
351 ret = logfile_write(file_info, data, data_len);
352 osal_mutex_unlock(&g_instance_mutex);
353 return ret;
354 }
355
uapi_logfile_init(void)356 errcode_t uapi_logfile_init(void)
357 {
358 if (g_instance_mutex.mutex != NULL) {
359 return ERRCODE_SUCC;
360 }
361
362 if (osal_mutex_init(&g_instance_mutex) != OSAL_SUCCESS) {
363 return ERRCODE_DFX_LOGFILE_MUTEX_FAILURE;
364 }
365 return ERRCODE_SUCC;
366 }
367
logfile_open(store_file_info_t * file_info)368 STATIC errcode_t logfile_open(store_file_info_t *file_info)
369 {
370 errcode_t ret = ERRCODE_SUCC;
371 /* 判断文件是否打开 */
372 if (file_info->fd > 0) {
373 return ERRCODE_DFX_LOGFILE_ALREADY_OPEN;
374 }
375
376 #if defined(CONFIG_DFX_SUPPORT_FILE_SYSTEM) && (CONFIG_DFX_SUPPORT_FILE_SYSTEM == DFX_NO)
377 if (file_info->file_cfg.enable_cache != 1) {
378 return ERRCODE_INVALID_PARAM;
379 }
380
381 if (logfile_flash_prepare(file_info) != ERRCODE_SUCC) {
382 ret = ERRCODE_DFX_LOGFILE_FLASH_PREPARE_FAIL;
383 goto err;
384 }
385 file_info->fd = (int32_t)file_info->type + 1; /* 在无文件系统场景下fd作为open成功的标记 */
386 #else
387 if (file_info->file_cfg.path == NULL || file_info->file_cfg.name == NULL) {
388 return ERRCODE_INVALID_PARAM;
389 }
390
391 if (logfile_create_path(&(file_info->file_cfg)) != ERRCODE_SUCC) {
392 ret = ERRCODE_DFX_LOGFILE_MKDIR_FATAL;
393 goto err;
394 }
395
396 ret = logfile_prepare_file_fd(file_info, &(file_info->file_cfg));
397 if (ret != ERRCODE_SUCC) {
398 goto err;
399 }
400 #endif
401 if (file_info->file_cfg.enable_cache != 0) {
402 ret = logfile_create_cache(file_info, &(file_info->file_cfg));
403 if (ret != ERRCODE_SUCC) {
404 goto err;
405 }
406 ret = logfile_create_thread();
407 if (ret != ERRCODE_SUCC) {
408 goto err;
409 }
410 }
411 file_info->run_flag = true;
412 return ERRCODE_SUCC;
413 err:
414 logfile_free_file_info(file_info);
415 return ret;
416 }
417
uapi_logfile_open(store_service_t service_type,const store_file_cfg_t * cfg)418 errcode_t uapi_logfile_open(store_service_t service_type, const store_file_cfg_t *cfg)
419 {
420 errcode_t ret;
421 if (service_type >= STORE_MAX || cfg == NULL) {
422 return ERRCODE_INVALID_PARAM;
423 }
424
425 store_file_info_t *file_info = &(g_logfile_manage.file_info[service_type]);
426 file_info->type = service_type;
427 file_info->file_cfg = *cfg;
428
429 osal_mutex_lock(&g_instance_mutex);
430 ret = logfile_open(file_info);
431 osal_mutex_unlock(&g_instance_mutex);
432 return ret;
433 }
434
logfile_close(store_file_info_t * file_info)435 STATIC errcode_t logfile_close(store_file_info_t *file_info)
436 {
437 /* 如果句柄为NULL,说明已经close */
438 if (file_info->fd == 0) {
439 return ERRCODE_SUCC;
440 }
441
442 file_info->run_flag = false;
443 if (file_info->file_cfg.enable_cache == 1) {
444 /* 等待线程执行完成 */
445 while (file_info->finish_flag == false) {
446 osal_msleep(CLOSE_SLEEP_PERIOD);
447 }
448 }
449
450 logfile_free_file_info(file_info);
451
452 uint32_t i;
453 for (i = 0; i < STORE_MAX; i++) {
454 if (g_logfile_manage.file_info[i].fd != 0) {
455 break;
456 }
457 }
458 /* 如果全部文件关闭,删除线程和Timer */
459 if (i >= STORE_MAX) {
460 logfile_free_os_resouce();
461 }
462
463 return ERRCODE_SUCC;
464 }
465
uapi_logfile_close(store_service_t service_type)466 errcode_t uapi_logfile_close(store_service_t service_type)
467 {
468 errcode_t ret;
469 if (service_type >= STORE_MAX) {
470 return ERRCODE_INVALID_PARAM;
471 }
472
473 store_file_info_t *file_info = &(g_logfile_manage.file_info[service_type]);
474
475 osal_mutex_lock(&g_instance_mutex);
476 ret = logfile_close(file_info);
477 osal_mutex_unlock(&g_instance_mutex);
478 return ret;
479 }
480
uapi_logfile_fsync(store_service_t service_type)481 errcode_t uapi_logfile_fsync(store_service_t service_type)
482 {
483 if (service_type >= STORE_MAX) {
484 return ERRCODE_INVALID_PARAM;
485 }
486
487 store_file_info_t *file_info = &(g_logfile_manage.file_info[service_type]);
488 if (file_info->fd == 0) {
489 return ERRCODE_SUCC;
490 }
491
492 #if CONFIG_DFX_SUPPORT_FILE_SYSTEM == DFX_YES
493 osal_mutex_lock(&g_instance_mutex);
494 fsync(file_info->fd);
495 osal_mutex_unlock(&g_instance_mutex);
496 #endif
497
498 return ERRCODE_SUCC;
499 }
500
uapi_logfile_suspend(store_service_t service_type)501 errcode_t uapi_logfile_suspend(store_service_t service_type)
502 {
503 if (service_type >= STORE_MAX) {
504 return ERRCODE_INVALID_PARAM;
505 }
506
507 store_file_info_t *file_info = &(g_logfile_manage.file_info[service_type]);
508 osal_mutex_lock(&g_instance_mutex);
509 file_info->run_flag = false;
510 osal_mutex_unlock(&g_instance_mutex);
511 return ERRCODE_SUCC;
512 }
513
uapi_logfile_resume(store_service_t service_type)514 errcode_t uapi_logfile_resume(store_service_t service_type)
515 {
516 if (service_type >= STORE_MAX) {
517 return ERRCODE_INVALID_PARAM;
518 }
519
520 store_file_info_t *file_info = &(g_logfile_manage.file_info[service_type]);
521 osal_mutex_lock(&g_instance_mutex);
522 file_info->run_flag = true;
523 osal_mutex_unlock(&g_instance_mutex);
524 return ERRCODE_SUCC;
525 }
526
uapi_logfile_reset(store_service_t service_type,store_file_cfg_t * cfg)527 errcode_t uapi_logfile_reset(store_service_t service_type, store_file_cfg_t *cfg)
528 {
529 errcode_t ret;
530 if (service_type >= STORE_MAX || cfg == NULL) {
531 return ERRCODE_INVALID_PARAM;
532 }
533
534 store_file_info_t *file_info = &(g_logfile_manage.file_info[service_type]);
535 osal_mutex_lock(&g_instance_mutex);
536 /* 判断文件是否打开 */
537 if (file_info->fd > 0) {
538 osal_mutex_unlock(&g_instance_mutex);
539 return ERRCODE_DFX_LOGFILE_ALREADY_OPEN;
540 }
541
542 #if defined(CONFIG_DFX_SUPPORT_FILE_SYSTEM) && (CONFIG_DFX_SUPPORT_FILE_SYSTEM == DFX_NO)
543 ret = logfile_flash_erase(service_type, cfg);
544 #else
545 ret = logfile_remove_files(service_type, cfg);
546 #endif
547 osal_mutex_unlock(&g_instance_mutex);
548 return ret;
549 }
550
551 #endif /* CONFIG_DFX_SUPPORT_OFFLINE_LOG_FILE */