• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */