/
usr
/
src
/
file_protector-1.1-1506
/
File Upload :
llllll
Current File: //usr/src/file_protector-1.1-1506/task_info_map.c
/** @file @brief Process (aka task) info storage @details Copyright (c) 2017-2021 Acronis International GmbH @author Ivan Matveev (ivan.matveev@acronis.com) @since $Id: $ */ #include "task_info_map.h" #include "compat.h" #include "debug.h" #include "memory.h" #include <linux/mm.h> // get_task_exe_file() typedef struct task_info_map_s { spinlock_t spinlock; struct rb_root root; spinlock_t exited_list_spinlock; struct list_head exited_list; } task_info_map_t; static task_info_map_t task_info_map; const char *task_status_to_string(task_status_t status) { switch (status) { #define CASE_TS_RETURN(t) case TS_##t: return #t CASE_TS_RETURN(UNKNOWN); CASE_TS_RETURN(IGNORE); CASE_TS_RETURN(WHITE); CASE_TS_RETURN(BLACK); CASE_TS_RETURN(GREY); #undef CASE_TS_RETURN default: return "?"; } } static task_info_t *task_info_init(task_info_t *task_info, pid_t pid) { DPRINTF("task_info=%p pid=%i", task_info, pid); RB_CLEAR_NODE(&task_info->rb_node); task_info->pid = pid; atomic_set(&task_info->ref_cnt, 1); spin_lock_init(&task_info->spinlock); task_info->status = TS_UNKNOWN; /* struct path { struct vfsmount *mnt; struct dentry *dentry; }; */ task_info->exe_path = (struct path){}; INIT_LIST_HEAD(&task_info->exited_list_item); return task_info; } static task_info_t *task_info_new(pid_t pid) { task_info_t *task_info = mem_alloc0(sizeof(task_info_t)); if (task_info) { task_info_init(task_info, pid); } return task_info; } task_info_t *task_info_ref(task_info_t *task_info) { atomic_inc(&task_info->ref_cnt); return task_info; } static void task_info_free(task_info_t *task_info) { DPRINTF("task_info=%p", task_info); // Note: 'path_put(&path={})' is safe path_put(&task_info->exe_path); mem_free(task_info); } void task_info_unref(task_info_t *task_info) { DPRINTF("pid=%d ref_cnt=%d", task_info->pid, atomic_read(&task_info->ref_cnt)); if (atomic_dec_and_test(&task_info->ref_cnt)) { task_info_free(task_info); } } int task_info_map_init(void) { DPRINTF(""); spin_lock_init(&task_info_map.spinlock); task_info_map.root = RB_ROOT; spin_lock_init(&task_info_map.exited_list_spinlock); INIT_LIST_HEAD(&task_info_map.exited_list); return 0; } void task_info_map_down(void) { task_info_map_clear(); } void task_info_map_clear(void) { struct rb_root root; struct rb_node *node; DPRINTF(""); task_info_map_delete_exited(); spin_lock(&task_info_map.spinlock); root = task_info_map.root; task_info_map.root = RB_ROOT; spin_unlock(&task_info_map.spinlock); node = root.rb_node; while (node) { task_info_t *task_info = rb_entry(node, task_info_t, rb_node); rb_erase(&task_info->rb_node, &root); task_info_unref(task_info); node = root.rb_node; } } task_info_t *task_info_lookup(pid_t pid) { struct rb_node *node; task_info_t *task_info = NULL; DPRINTF("pid=%d", pid); spin_lock(&task_info_map.spinlock); node = task_info_map.root.rb_node; while (node) { task_info_t *node_task_info = rb_entry(node, task_info_t, rb_node); pid_t node_pid = node_task_info->pid; if (pid < node_pid) { node = node->rb_left; } else if (pid > node_pid) { node = node->rb_right; } else { task_info = task_info_ref(node_task_info); break; } } spin_unlock(&task_info_map.spinlock); DPRINTF_RATELIMITED("task_info=%p pid=%d", task_info, pid); return task_info; } static task_info_t *task_info_map_insert(task_info_t *new_task_info) { pid_t pid = new_task_info->pid; struct rb_node *parent = NULL; struct rb_node **link; DPRINTF_RATELIMITED("new_task_info=%p pid=%i", new_task_info, pid); spin_lock(&task_info_map.spinlock); link = &(task_info_map.root.rb_node); while (*link) { task_info_t *node_task_info; pid_t node_pid; parent = *link; node_task_info = rb_entry(parent, task_info_t, rb_node); node_pid = node_task_info->pid; if (pid < node_pid) { link = &parent->rb_left; } else if (pid > node_pid) { link = &parent->rb_right; } else { // collision DPRINTF_RATELIMITED("collision"); task_info_ref(node_task_info); spin_unlock(&task_info_map.spinlock); return node_task_info; } } // do 'inc' for 'task_info_map.root' task_info_ref(new_task_info); rb_link_node(&new_task_info->rb_node, parent, link); rb_insert_color(&new_task_info->rb_node, &task_info_map.root); DPRINTF_RATELIMITED("inserted"); spin_unlock(&task_info_map.spinlock); return new_task_info; } // Warning: May block! task_info_t *task_info_get(pid_t pid) { task_info_t *task_info; task_info_t *new_task_info; DPRINTF_RATELIMITED("pid=%d", pid); task_info = task_info_lookup(pid); if (task_info) { DPRINTF_RATELIMITED("pid=%i is already in the map (task_info=%p)", pid, task_info); return task_info; } new_task_info = task_info_new(pid); if (!new_task_info) { DPRINTF_RATELIMITED("out of memory"); return NULL; } task_info = task_info_map_insert(new_task_info); if (task_info != new_task_info) { // collision DPRINTF_RATELIMITED("collision"); task_info_unref(new_task_info); } return task_info; } int task_info_map_del(pid_t pid) { task_info_t *task_info; DPRINTF("pid=%d", pid); task_info = task_info_lookup(pid); if (!task_info) { WPRINTF("pid=%d is missing in the map", pid); return -ENOENT; } spin_lock(&task_info_map.spinlock); rb_erase(&task_info->rb_node, &task_info_map.root); spin_unlock(&task_info_map.spinlock); // undo 'inc' done for 'task_info_map.root' task_info_unref(task_info); // undo 'inc' done in 'task_info_lookup()' task_info_unref(task_info); DPRINTF("pid=%d", pid); return 0; } // FIXME: eliminate 'task_info_status_get()' task_status_t task_info_status_get(pid_t pid) { task_info_t *task_info; task_status_t status; task_info = task_info_lookup(pid); if (!task_info) { status = TS_UNKNOWN; } else { // FIXME: is it really necessary to protect 'task_status_t' with spinlock? spin_lock(&task_info->spinlock); status = task_info->status; spin_unlock(&task_info->spinlock); task_info_unref(task_info); } return status; } // Warning: May block! int task_info_status_set(pid_t pid, task_status_t status) { task_info_t *task_info; DPRINTF("pid=%i status=%i/%s", pid, status, task_status_to_string(status)); task_info = task_info_get(pid); if (!task_info) { WPRINTF("'%s(pid=%i)' failure", "task_info_get", pid); return -ENOMEM; } // FIXME: is it really necessary to protect 'task_status_t' with spinlock? spin_lock(&task_info->spinlock); task_info->status = status; spin_unlock(&task_info->spinlock); task_info_unref(task_info); return 0; } void task_info_map_on_exit_event(pid_t tgid, pid_t pid) { task_info_t *task_info = task_info_lookup(pid); if (!task_info) { DPRINTF("%u:%u is missing in 'task_info_map'", tgid, pid); } else { spin_lock(&task_info_map.exited_list_spinlock); if (!list_empty(&task_info->exited_list_item)) { WPRINTF("%u:%u is already in 'exited list'", tgid, pid); } else { // do 'inc' for 'task_info_map.exited_list' task_info_ref(task_info); list_add_tail(&task_info->exited_list_item, &task_info_map.exited_list); DPRINTF("%u:%u task_info=%p is added to 'exited list'", tgid, pid, task_info); } spin_unlock(&task_info_map.exited_list_spinlock); task_info_unref(task_info); } } void task_info_map_delete_exited(void) { for (;;) { task_info_t *task_info; pid_t pid; spin_lock(&task_info_map.exited_list_spinlock); if (list_empty(&task_info_map.exited_list)) { spin_unlock(&task_info_map.exited_list_spinlock); return; } task_info = list_entry(task_info_map.exited_list.next, task_info_t, exited_list_item); list_del_init(&task_info->exited_list_item); spin_unlock(&task_info_map.exited_list_spinlock); pid = task_info->pid; DPRINTF("deleting task_info=%p with pid=%u", task_info, pid); task_info_map_del(pid); // undo 'inc' done for 'task_info_map.exited_list' task_info_unref(task_info); } }
Copyright ©2k19 -
Hexid
|
Tex7ure