1 /*
2 * Copyright (C) 2022 Huawei Technologies Co., Ltd.
3 * Decription: cmdmonitor function, monitor every cmd which is sent to TEE.
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14 #include "cmdmonitor.h"
15 #include <linux/workqueue.h>
16 #include <linux/kthread.h>
17 #include <linux/list.h>
18 #include <linux/sched.h>
19 #include <linux/pid.h>
20 #include <linux/delay.h>
21 #include <linux/mutex.h>
22 #include <linux/timer.h>
23 #include <linux/kernel.h>
24 #include <linux/version.h>
25 #include <securec.h>
26 #if (KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE)
27 #include <linux/sched/task.h>
28 #endif
29
30 #ifdef CONFIG_TEE_LOG_EXCEPTION
31 #include <huawei_platform/log/imonitor.h>
32 #define IMONITOR_TA_CRASH_EVENT_ID 901002003
33 #define IMONITOR_MEMSTAT_EVENT_ID 940007001
34 #define IMONITOR_TAMEMSTAT_EVENT_ID 940007002
35 #endif
36
37 #include "tc_ns_log.h"
38 #include "smc_smp.h"
39 #include "internal_functions.h"
40 #include "mailbox_mempool.h"
41 #include "tlogger.h"
42 #include "log_cfg_api.h"
43 #include "tui.h"
44
45 static int g_cmd_need_archivelog;
46 static LIST_HEAD(g_cmd_monitor_list);
47 static int g_cmd_monitor_list_size;
48 /* report 2 hours */
49 static const long long g_memstat_report_freq = 2 * 60 * 60 * 1000;
50 #define MAX_CMD_MONITOR_LIST 200
51 #define MAX_AGENT_CALL_COUNT 5000
52 static DEFINE_MUTEX(g_cmd_monitor_lock);
53
54 /* independent wq to avoid block system_wq */
55 static struct workqueue_struct *g_cmd_monitor_wq;
56 static struct delayed_work g_cmd_monitor_work;
57 static struct delayed_work g_cmd_monitor_work_archive;
58 static struct delayed_work g_mem_stat;
59 static int g_tee_detect_ta_crash;
60 static struct tc_uuid g_crashed_ta_uuid;
61
get_time_spec(struct time_spec * time)62 void get_time_spec(struct time_spec *time)
63 {
64 if (!time)
65 return;
66 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0))
67 time->ts = current_kernel_time();
68 #else
69 ktime_get_coarse_ts64(&time->ts);
70 #endif
71 }
72
schedule_memstat_work(struct delayed_work * work,unsigned long delay)73 static void schedule_memstat_work(struct delayed_work *work,
74 unsigned long delay)
75 {
76 schedule_delayed_work(work, delay);
77 }
78
schedule_cmd_monitor_work(struct delayed_work * work,unsigned long delay)79 static void schedule_cmd_monitor_work(struct delayed_work *work,
80 unsigned long delay)
81 {
82 if (g_cmd_monitor_wq)
83 queue_delayed_work(g_cmd_monitor_wq, work, delay);
84 else
85 schedule_delayed_work(work, delay);
86 }
87
tzdebug_memstat(void)88 void tzdebug_memstat(void)
89 {
90 schedule_memstat_work(&g_mem_stat, usecs_to_jiffies(S_TO_MS));
91 }
92
tzdebug_archivelog(void)93 void tzdebug_archivelog(void)
94 {
95 schedule_cmd_monitor_work(&g_cmd_monitor_work_archive,
96 usecs_to_jiffies(0));
97 }
98
cmd_monitor_ta_crash(int32_t type,const uint8_t * ta_uuid,uint32_t uuid_len)99 void cmd_monitor_ta_crash(int32_t type, const uint8_t *ta_uuid, uint32_t uuid_len)
100 {
101 g_tee_detect_ta_crash = type;
102 if (g_tee_detect_ta_crash != TYPE_CRASH_TEE &&
103 ta_uuid != NULL && uuid_len == sizeof(struct tc_uuid))
104 (void)memcpy_s(&g_crashed_ta_uuid, sizeof(g_crashed_ta_uuid),
105 ta_uuid, uuid_len);
106 tzdebug_archivelog();
107 fault_monitor_start(type);
108 }
109
get_pid_name(pid_t pid,char * comm,size_t size)110 static int get_pid_name(pid_t pid, char *comm, size_t size)
111 {
112 struct task_struct *task = NULL;
113 int sret;
114
115 if (size <= TASK_COMM_LEN - 1 || !comm)
116 return -1;
117
118 rcu_read_lock();
119
120 #ifndef CONFIG_TZDRIVER_MODULE
121 task = find_task_by_vpid(pid);
122 #else
123 task = pid_task(find_vpid(pid), PIDTYPE_PID);
124 #endif
125 if (task)
126 get_task_struct(task);
127 rcu_read_unlock();
128 if (!task) {
129 tloge("get task failed\n");
130 return -1;
131 }
132
133 sret = strncpy_s(comm, size, task->comm, strlen(task->comm));
134 if (sret != 0)
135 tloge("strncpy failed: errno = %d\n", sret);
136 put_task_struct(task);
137
138 return sret;
139 }
140
is_thread_reported(pid_t tid)141 bool is_thread_reported(pid_t tid)
142 {
143 bool ret = false;
144 struct cmd_monitor *monitor = NULL;
145
146 mutex_lock(&g_cmd_monitor_lock);
147 list_for_each_entry(monitor, &g_cmd_monitor_list, list) {
148 if (monitor->tid == tid && !is_tui_in_use(monitor->tid)) {
149 ret = (monitor->is_reported ||
150 monitor->agent_call_count >
151 MAX_AGENT_CALL_COUNT);
152 break;
153 }
154 }
155 mutex_unlock(&g_cmd_monitor_lock);
156 return ret;
157 }
158
159 #ifdef CONFIG_TEE_LOG_EXCEPTION
160 #define FAIL_RET (-1)
161 #define SUCC_RET 0
162
send_memstat_packet(const struct tee_mem * meminfo)163 static int send_memstat_packet(const struct tee_mem *meminfo)
164 {
165 struct imonitor_eventobj *memstat = NULL;
166 uint32_t result = 0;
167 struct time_spec nowtime;
168 int ret;
169 get_time_spec(&nowtime);
170
171 memstat = imonitor_create_eventobj(IMONITOR_MEMSTAT_EVENT_ID);
172 if (!memstat) {
173 tloge("create eventobj failed\n");
174 return FAIL_RET;
175 }
176
177 result |= (uint32_t)imonitor_set_param_integer_v2(memstat, "totalmem", meminfo->total_mem);
178 result |= (uint32_t)imonitor_set_param_integer_v2(memstat, "mem", meminfo->pmem);
179 result |= (uint32_t)imonitor_set_param_integer_v2(memstat, "freemem", meminfo->free_mem);
180 result |= (uint32_t)imonitor_set_param_integer_v2(memstat, "freememmin", meminfo->free_mem_min);
181 result |= (uint32_t)imonitor_set_param_integer_v2(memstat, "tanum", meminfo->ta_num);
182 result |= (uint32_t)imonitor_set_time(memstat, nowtime.ts.tv_sec);
183 if (result) {
184 tloge("set param integer1 failed ret=%u\n", result);
185 imonitor_destroy_eventobj(memstat);
186 return FAIL_RET;
187 }
188
189 ret = imonitor_send_event(memstat);
190 imonitor_destroy_eventobj(memstat);
191 if (ret <= 0) {
192 tloge("imonitor send memstat packet failed\n");
193 return FAIL_RET;
194 }
195 return SUCC_RET;
196 }
197
report_imonitor(const struct tee_mem * meminfo)198 void report_imonitor(const struct tee_mem *meminfo)
199 {
200 int ret;
201 uint32_t result = 0;
202 uint32_t i;
203 struct imonitor_eventobj *pamemobj = NULL;
204 struct time_spec nowtime;
205 get_time_spec(&nowtime);
206
207 if (!meminfo)
208 return;
209
210 if (meminfo->ta_num > MEMINFO_TA_MAX)
211 return;
212
213 if (send_memstat_packet(meminfo))
214 return;
215
216 for (i = 0; i < meminfo->ta_num; i++) {
217 pamemobj = imonitor_create_eventobj(IMONITOR_TAMEMSTAT_EVENT_ID);
218 if (!pamemobj) {
219 tloge("create obj failed\n");
220 break;
221 }
222
223 result |= (uint32_t)imonitor_set_param_string_v2(pamemobj, "NAME", meminfo->ta_mem_info[i].ta_name);
224 result |= (uint32_t)imonitor_set_param_integer_v2(pamemobj, "MEM", meminfo->ta_mem_info[i].pmem);
225 result |= (uint32_t)imonitor_set_param_integer_v2(pamemobj, "MEMMAX", meminfo->ta_mem_info[i].pmem_max);
226 result |= (uint32_t)imonitor_set_param_integer_v2(pamemobj, "MEMLIMIT", meminfo->ta_mem_info[i].pmem_limit);
227 result |= (uint32_t)imonitor_set_time(pamemobj, nowtime.ts.tv_sec);
228 if (result) {
229 tloge("set param integer2 failed ret=%d\n", result);
230 imonitor_destroy_eventobj(pamemobj);
231 return;
232 }
233 ret = imonitor_send_event(pamemobj);
234 imonitor_destroy_eventobj(pamemobj);
235 if (ret <= 0) {
236 tloge("imonitor send pamem packet failed\n");
237 break;
238 }
239 }
240 }
241 #endif
242
memstat_report(void)243 static void memstat_report(void)
244 {
245 int ret;
246 struct tee_mem *meminfo = NULL;
247
248 meminfo = mailbox_alloc(sizeof(*meminfo), MB_FLAG_ZERO);
249 if (!meminfo) {
250 tloge("mailbox alloc failed\n");
251 return;
252 }
253
254 ret = get_tee_meminfo(meminfo);
255 #ifdef CONFIG_TEE_LOG_EXCEPTION
256 if (ret == 0) {
257 tlogd("report imonitor\n");
258 report_imonitor(meminfo);
259 }
260 #endif
261 if (ret != 0)
262 tlogd("get meminfo failed\n");
263
264 mailbox_free(meminfo);
265 }
266
memstat_work(struct work_struct * work)267 static void memstat_work(struct work_struct *work)
268 {
269 (void)(work);
270 memstat_report();
271 }
272
cmd_monitor_reset_context(void)273 void cmd_monitor_reset_context(void)
274 {
275 struct cmd_monitor *monitor = NULL;
276 pid_t pid = current->tgid;
277 pid_t tid = current->pid;
278
279 mutex_lock(&g_cmd_monitor_lock);
280 list_for_each_entry(monitor, &g_cmd_monitor_list, list) {
281 if (monitor->pid == pid && monitor->tid == tid) {
282 get_time_spec(&monitor->sendtime);
283 if (monitor->agent_call_count + 1 < 0)
284 tloge("agent call count add overflow\n");
285 else
286 monitor->agent_call_count++;
287 break;
288 }
289 }
290 mutex_unlock(&g_cmd_monitor_lock);
291 }
292
293 #ifdef CONFIG_TEE_LOG_EXCEPTION
294 static struct time_spec g_memstat_check_time;
295 static bool g_after_loader = false;
296
auto_report_memstat(void)297 static void auto_report_memstat(void)
298 {
299 long long timedif;
300 struct time_spec nowtime;
301 get_time_spec(&nowtime);
302
303 /*
304 * get time value D (timedif=nowtime-sendtime),
305 * we do not care about overflow
306 * 1 year means 1000 * (60*60*24*365) = 0x757B12C00
307 * only 5bytes, will not overflow
308 */
309 timedif = S_TO_MS * (nowtime.ts.tv_sec - g_memstat_check_time.ts.tv_sec) +
310 (nowtime.ts.tv_nsec - g_memstat_check_time.ts.tv_nsec) / S_TO_US;
311 if (timedif > g_memstat_report_freq && g_after_loader) {
312 tlogi("cmdmonitor auto report memstat\n");
313 memstat_report();
314 g_memstat_check_time = nowtime;
315 }
316
317 if (!g_after_loader) {
318 g_memstat_check_time = nowtime;
319 g_after_loader = true;
320 }
321 }
322 #endif
323
324 /*
325 * if one session timeout, monitor will print timedifs every step[n] in seconds,
326 * if lasted more then 360s, monitor will print timedifs every 360s.
327 */
328 const int32_t g_timer_step[] = {1, 1, 1, 2, 5, 10, 40, 120, 180, 360};
329 const int32_t g_timer_nums = sizeof(g_timer_step) / sizeof(int32_t);
show_timeout_cmd_info(struct cmd_monitor * monitor)330 static void show_timeout_cmd_info(struct cmd_monitor *monitor)
331 {
332 long long timedif, timedif2;
333 struct time_spec nowtime;
334 int32_t time_in_sec;
335 get_time_spec(&nowtime);
336
337 /*
338 * 1 year means 1000 * (60*60*24*365) = 0x757B12C00
339 * only 5bytes, so timedif (timedif=nowtime-sendtime) will not overflow
340 */
341 timedif = S_TO_MS * (nowtime.ts.tv_sec - monitor->sendtime.ts.tv_sec) +
342 (nowtime.ts.tv_nsec - monitor->sendtime.ts.tv_nsec) / S_TO_US;
343
344 /* timeout to 10s, we log the teeos log, and report */
345 if ((timedif > CMD_MAX_EXECUTE_TIME * S_TO_MS) && (!monitor->is_reported)) {
346 monitor->is_reported = true;
347 tloge("[cmd_monitor_tick] pid=%d,pname=%s,tid=%d, "
348 "tname=%s, lastcmdid=%u, agent call count:%d, "
349 "running with timedif=%lld ms and report\n",
350 monitor->pid, monitor->pname, monitor->tid,
351 monitor->tname, monitor->lastcmdid,
352 monitor->agent_call_count, timedif);
353 /* threads out of white table need info dump */
354 tloge("monitor: pid-%d", monitor->pid);
355 if (!is_tui_in_use(monitor->tid)) {
356 show_cmd_bitmap();
357 g_cmd_need_archivelog = 1;
358 wakeup_tc_siq(SIQ_DUMP_TIMEOUT);
359 }
360 }
361
362 timedif2 = S_TO_MS * (nowtime.ts.tv_sec - monitor->lasttime.ts.tv_sec) +
363 (nowtime.ts.tv_nsec - monitor->lasttime.ts.tv_nsec) / S_TO_US;
364 time_in_sec = monitor->timer_index >= g_timer_nums ?
365 g_timer_step[g_timer_nums - 1] : g_timer_step[monitor->timer_index];
366 if (timedif2 > time_in_sec * S_TO_MS) {
367 monitor->lasttime = nowtime;
368 monitor->timer_index = monitor->timer_index >= (int32_t)sizeof(g_timer_step) ?
369 (int32_t)sizeof(g_timer_step) : (monitor->timer_index + 1);
370 tlogi("[cmd_monitor_tick] pid=%d,pname=%s,tid=%d, "
371 "lastcmdid=%u,agent call count:%d,timedif=%lld ms\n",
372 monitor->pid, monitor->pname, monitor->tid,
373 monitor->lastcmdid, monitor->agent_call_count,
374 timedif);
375 }
376 }
377
cmd_monitor_tick(void)378 static void cmd_monitor_tick(void)
379 {
380 struct cmd_monitor *monitor = NULL;
381 struct cmd_monitor *tmp = NULL;
382
383 mutex_lock(&g_cmd_monitor_lock);
384 list_for_each_entry_safe(monitor, tmp, &g_cmd_monitor_list, list) {
385 if (monitor->returned) {
386 g_cmd_monitor_list_size--;
387 tlogd("[cmd_monitor_tick] pid=%d,pname=%s,tid=%d, "
388 "tname=%s,lastcmdid=%u,count=%d,agent call count=%d, "
389 "timetotal=%lld us returned, remained command(s)=%d\n",
390 monitor->pid, monitor->pname, monitor->tid, monitor->tname,
391 monitor->lastcmdid, monitor->count, monitor->agent_call_count,
392 monitor->timetotal, g_cmd_monitor_list_size);
393 list_del(&monitor->list);
394 kfree(monitor);
395 continue;
396 }
397 show_timeout_cmd_info(monitor);
398 }
399
400 /* if have cmd in monitor list, we need tick */
401 if (g_cmd_monitor_list_size > 0)
402 schedule_cmd_monitor_work(&g_cmd_monitor_work, usecs_to_jiffies(S_TO_US));
403 mutex_unlock(&g_cmd_monitor_lock);
404 #ifdef CONFIG_TEE_LOG_EXCEPTION
405 auto_report_memstat();
406 #endif
407 }
408
cmd_monitor_tickfn(struct work_struct * work)409 static void cmd_monitor_tickfn(struct work_struct *work)
410 {
411 (void)(work);
412 cmd_monitor_tick();
413 /* check tlogcat if have new log */
414 tz_log_write();
415 }
416
417 #define MAX_CRASH_INFO_LEN 100
cmd_monitor_archivefn(struct work_struct * work)418 static void cmd_monitor_archivefn(struct work_struct *work)
419 {
420 (void)(work);
421
422 if (tlogger_store_msg(CONFIG_TEE_LOG_ACHIVE_PATH,
423 sizeof(CONFIG_TEE_LOG_ACHIVE_PATH)) < 0)
424 tloge("[cmd_monitor_tick]tlogger store lastmsg failed\n");
425
426 if (g_tee_detect_ta_crash == TYPE_CRASH_TEE) {
427 tloge("detect teeos crash, panic\n");
428 report_log_system_panic();
429 } else if (g_tee_detect_ta_crash == TYPE_CRASH_TA ||
430 g_tee_detect_ta_crash == TYPE_KILLED_TA) {
431 #ifdef CONFIG_TEE_LOG_EXCEPTION
432 const char crash_prefix[] = "ta crash: ";
433 const char killed_prefix[] = "ta timeout and killed: ";
434 const char crash_info_get_failed[] = "ta crash: get uuid failed";
435 char buffer[MAX_CRASH_INFO_LEN] = {0};
436 const char *crash_info = buffer;
437 int ret = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1,
438 "%s%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
439 (g_tee_detect_ta_crash == TYPE_CRASH_TA) ? crash_prefix : killed_prefix,
440 g_crashed_ta_uuid.time_low, g_crashed_ta_uuid.time_mid,
441 g_crashed_ta_uuid.timehi_and_version,
442 g_crashed_ta_uuid.clockseq_and_node[0], g_crashed_ta_uuid.clockseq_and_node[1],
443 g_crashed_ta_uuid.clockseq_and_node[2], g_crashed_ta_uuid.clockseq_and_node[3],
444 g_crashed_ta_uuid.clockseq_and_node[4], g_crashed_ta_uuid.clockseq_and_node[5],
445 g_crashed_ta_uuid.clockseq_and_node[6], g_crashed_ta_uuid.clockseq_and_node[7]);
446 if (ret <= 0) {
447 tlogw("append crash info failed\n");
448 crash_info = crash_info_get_failed;
449 }
450 if (teeos_log_exception_archive(IMONITOR_TA_CRASH_EVENT_ID, crash_info) < 0)
451 tloge("log exception archive failed\n");
452 (void)memset_s(&g_crashed_ta_uuid, sizeof(g_crashed_ta_uuid), 0, sizeof(g_crashed_ta_uuid));
453 #endif
454 }
455
456 g_tee_detect_ta_crash = 0;
457 }
458
init_monitor_locked(void)459 static struct cmd_monitor *init_monitor_locked(void)
460 {
461 struct cmd_monitor *newitem = NULL;
462
463 newitem = kzalloc(sizeof(*newitem), GFP_KERNEL);
464 if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)newitem)) {
465 tloge("[cmd_monitor_tick]kzalloc failed\n");
466 return NULL;
467 }
468
469 get_time_spec(&newitem->sendtime);
470 newitem->lasttime = newitem->sendtime;
471 newitem->timer_index = 0;
472 newitem->count = 1;
473 newitem->agent_call_count = 0;
474 newitem->returned = false;
475 newitem->is_reported = false;
476 newitem->pid = current->tgid;
477 newitem->tid = current->pid;
478 if (get_pid_name(newitem->pid, newitem->pname,
479 sizeof(newitem->pname)) != 0)
480 newitem->pname[0] = '\0';
481 if (get_pid_name(newitem->tid, newitem->tname,
482 sizeof(newitem->tname)) != 0)
483 newitem->tname[0] = '\0';
484 INIT_LIST_HEAD(&newitem->list);
485 list_add_tail(&newitem->list, &g_cmd_monitor_list);
486 g_cmd_monitor_list_size++;
487 return newitem;
488 }
489
cmd_monitor_log(const struct tc_ns_smc_cmd * cmd)490 struct cmd_monitor *cmd_monitor_log(const struct tc_ns_smc_cmd *cmd)
491 {
492 bool found_flag = false;
493 pid_t pid;
494 pid_t tid;
495 struct cmd_monitor *monitor = NULL;
496
497 if (!cmd)
498 return NULL;
499
500 pid = current->tgid;
501 tid = current->pid;
502 mutex_lock(&g_cmd_monitor_lock);
503 do {
504 list_for_each_entry(monitor, &g_cmd_monitor_list, list) {
505 if (monitor->pid == pid && monitor->tid == tid) {
506 found_flag = true;
507 /* restart */
508 get_time_spec(&monitor->sendtime);
509 monitor->lasttime = monitor->sendtime;
510 monitor->timer_index = 0;
511 monitor->count++;
512 monitor->returned = false;
513 monitor->is_reported = false;
514 monitor->lastcmdid = cmd->cmd_id;
515 monitor->agent_call_count = 0;
516 monitor->timetotal = 0;
517 break;
518 }
519 }
520
521 if (!found_flag) {
522 #ifndef CONFIG_BIG_SESSION
523 if (g_cmd_monitor_list_size > MAX_CMD_MONITOR_LIST - 1) {
524 tloge("monitor reach max node num\n");
525 monitor = NULL;
526 break;
527 }
528 #endif
529 monitor = init_monitor_locked();
530 if (!monitor) {
531 tloge("init monitor failed\n");
532 break;
533 }
534 monitor->lastcmdid = cmd->cmd_id;
535 /* the first cmd will cause timer */
536 if (g_cmd_monitor_list_size == 1)
537 schedule_cmd_monitor_work(&g_cmd_monitor_work,
538 usecs_to_jiffies(S_TO_US));
539 }
540 } while (0);
541 mutex_unlock(&g_cmd_monitor_lock);
542
543 return monitor;
544 }
545
cmd_monitor_logend(struct cmd_monitor * item)546 void cmd_monitor_logend(struct cmd_monitor *item)
547 {
548 struct time_spec nowtime;
549 long long timedif;
550
551 if (!item)
552 return;
553
554 get_time_spec(&nowtime);
555 /*
556 * get time value D (timedif=nowtime-sendtime),
557 * we do not care about overflow
558 * 1 year means 1000000 * (60*60*24*365) = 0x1CAE8C13E000
559 * only 6bytes, will not overflow
560 */
561 timedif = S_TO_US * (nowtime.ts.tv_sec - item->sendtime.ts.tv_sec) +
562 (nowtime.ts.tv_nsec - item->sendtime.ts.tv_nsec) / S_TO_MS;
563 item->timetotal += timedif;
564 item->returned = true;
565 }
566
do_cmd_need_archivelog(void)567 void do_cmd_need_archivelog(void)
568 {
569 if (g_cmd_need_archivelog == 1) {
570 g_cmd_need_archivelog = 0;
571 schedule_cmd_monitor_work(&g_cmd_monitor_work_archive,
572 usecs_to_jiffies(S_TO_US));
573 }
574 }
575
init_cmd_monitor(void)576 void init_cmd_monitor(void)
577 {
578 g_cmd_monitor_wq = alloc_workqueue("tz_cmd_monitor_wq",
579 WQ_UNBOUND, TZ_WQ_MAX_ACTIVE);
580 if (!g_cmd_monitor_wq)
581 tloge("alloc cmd monitor wq failed\n");
582 else
583 tz_workqueue_bind_mask(g_cmd_monitor_wq, 0);
584
585 INIT_DEFERRABLE_WORK((struct delayed_work *)
586 (uintptr_t)&g_cmd_monitor_work, cmd_monitor_tickfn);
587 INIT_DEFERRABLE_WORK((struct delayed_work *)
588 (uintptr_t)&g_cmd_monitor_work_archive, cmd_monitor_archivefn);
589 INIT_DEFERRABLE_WORK((struct delayed_work *)
590 (uintptr_t)&g_mem_stat, memstat_work);
591 }
592
free_cmd_monitor(void)593 void free_cmd_monitor(void)
594 {
595 struct cmd_monitor *monitor = NULL;
596 struct cmd_monitor *tmp = NULL;
597
598 mutex_lock(&g_cmd_monitor_lock);
599 list_for_each_entry_safe(monitor, tmp, &g_cmd_monitor_list, list) {
600 list_del(&monitor->list);
601 kfree(monitor);
602 }
603 mutex_unlock(&g_cmd_monitor_lock);
604
605 flush_delayed_work(&g_cmd_monitor_work);
606 flush_delayed_work(&g_cmd_monitor_work_archive);
607 flush_delayed_work(&g_mem_stat);
608 if (g_cmd_monitor_wq) {
609 flush_workqueue(g_cmd_monitor_wq);
610 destroy_workqueue(g_cmd_monitor_wq);
611 g_cmd_monitor_wq = NULL;
612 }
613 }
614