From 0cd313c8cdf658275049b43a2f9d6538d6fcd757 Mon Sep 17 00:00:00 2001 From: Vyacheslav Cherkashin Date: Thu, 3 Oct 2013 16:55:02 +0400 Subject: [PATCH] [FEATURE] add event_filter in swap_writer module Change-Id: I9f02dbf02dab36264f4a1f8e2e6f29d702ef7ea9 Signed-off-by: Vyacheslav Cherkashin --- writer/Kbuild | 3 +- writer/debugfs_writer.c | 133 ++++++++++++++++++++++++++++++++++++++++++-- writer/event_filter.c | 126 +++++++++++++++++++++++++++++++++++++++++ writer/event_filter.h | 53 ++++++++++++++++++ writer/swap_writer_module.c | 32 +++++++++-- 5 files changed, 338 insertions(+), 9 deletions(-) create mode 100644 writer/event_filter.c create mode 100644 writer/event_filter.h diff --git a/writer/Kbuild b/writer/Kbuild index 72d7ef3..8f15bde 100644 --- a/writer/Kbuild +++ b/writer/Kbuild @@ -3,4 +3,5 @@ EXTRA_CFLAGS := $(extra_cflags) obj-m := swap_writer.o swap_writer-y := swap_writer_module.o \ kernel_operations.o \ - debugfs_writer.o + debugfs_writer.o \ + event_filter.o diff --git a/writer/debugfs_writer.c b/writer/debugfs_writer.c index 9986a54..21c221b 100644 --- a/writer/debugfs_writer.c +++ b/writer/debugfs_writer.c @@ -26,9 +26,11 @@ #include #include #include +#include #include #include #include "swap_writer_module.h" +#include "event_filter.h" /* ============================================================================ @@ -81,6 +83,119 @@ static const struct file_operations fops_raw = { /* ============================================================================ + * === FOPS_AVAILABLE_FILTERS === + * ============================================================================ + */ +struct read_buf { + char *begin; + char *ptr; + char *end; +}; + +static void func_for_read(struct ev_filter *f, void *data) +{ + struct read_buf *rbuf = (struct read_buf *)data; + int len = strlen(f->name); + + if (rbuf->end - rbuf->ptr < len + 2) + return; + + if (rbuf->ptr != rbuf->begin) { + *rbuf->ptr = ' '; + ++rbuf->ptr; + } + + memcpy(rbuf->ptr, f->name, len); + rbuf->ptr += len; +} + +static ssize_t read_af(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + char buf[512]; + struct read_buf rbuf = { + .begin = buf, + .ptr = buf, + .end = buf + sizeof(buf) + }; + + event_filter_on_each(func_for_read, (void *)&rbuf); + + *rbuf.ptr = '\n'; + ++rbuf.ptr; + + return simple_read_from_buffer(user_buf, count, ppos, + rbuf.begin, rbuf.ptr - rbuf.begin); +} + +static const struct file_operations fops_available_filters = { + .read = read_af, + .llseek = default_llseek +}; + + + + + +/* ============================================================================ + * === FOPS_FILTER === + * ============================================================================ + */ +static ssize_t read_filter(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + const char *name = event_filter_get(); + int len = strlen(name); + char *buf; + ssize_t ret; + + buf = kmalloc(len + 2, GFP_KERNEL); + memcpy(buf, name, len); + + buf[len] = '\0'; + buf[len + 1] = '\n'; + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, len + 2); + kfree(buf); + + return ret; +} + +static ssize_t write_filter(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + enum { len = 32 }; + char buf[len], name[len]; + size_t buf_size; + ssize_t ret; + + buf_size = min(count, (size_t)(len - 1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + buf[len - 1] = '\0'; + ret = sscanf(buf, "%31s", name); + if (ret != 1) + return -EINVAL; + + ret = event_filter_set(name); + if (ret) + return -EINVAL; + + return count; +} + +static const struct file_operations fops_filter = { + .read = read_filter, + .write = write_filter, + .llseek = default_llseek +}; + + + + + +/* ============================================================================ * === INIT/EXIT === * ============================================================================ */ @@ -114,10 +229,20 @@ int init_debugfs_writer(void) return -ENOMEM; dentry = debugfs_create_file("raw", 0600, writer_dir, NULL, &fops_raw); - if (dentry == NULL) { - exit_debugfs_writer(); - return -ENOMEM; - } + if (dentry == NULL) + goto fail; + + dentry = debugfs_create_file("available_filters", 0600, writer_dir, NULL, &fops_available_filters); + if (dentry == NULL) + goto fail; + + dentry = debugfs_create_file("filter", 0600, writer_dir, NULL, &fops_filter); + if (dentry == NULL) + goto fail; return 0; + +fail: + exit_debugfs_writer(); + return -ENOMEM; } diff --git a/writer/event_filter.c b/writer/event_filter.c new file mode 100644 index 0000000..fdddd51 --- /dev/null +++ b/writer/event_filter.c @@ -0,0 +1,126 @@ +/* + * SWAP kernel features + * writer/event_filter.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Samsung Electronics, 2013 + * + * 2013 Vyacheslav Cherkashin + * + */ + + +#include +#include +#include "event_filter.h" + + +static LIST_HEAD(filter_list); + +static int func_none(struct task_struct *task) +{ + return 1; +} + +static struct ev_filter filter_none = { + .name = "all", + .filter = func_none +}; + +static struct ev_filter *filter_current = &filter_none; + +int check_event(struct task_struct *task) +{ + return filter_current->filter(task); +} + +static struct ev_filter *event_filter_find(const char *name) +{ + struct ev_filter *f, *tmp; + + list_for_each_entry_safe(f, tmp, &filter_list, list) { + if (strcmp(f->name, name) == 0) + return f; + } + + return NULL; +} + +int event_filter_register(struct ev_filter *f) +{ + if (event_filter_find(f->name)) + return -EINVAL; + + INIT_LIST_HEAD(&f->list); + list_add(&f->list, &filter_list); + + return 0; +} +EXPORT_SYMBOL_GPL(event_filter_register); + +void event_filter_unregister(struct ev_filter *f) +{ + struct ev_filter *filter, *tmp; + + if (filter_current == f) + filter_current = &filter_none; + + list_for_each_entry_safe(filter, tmp, &filter_list, list) { + if (filter == f) { + list_del(&filter->list); + break; + } + } +} +EXPORT_SYMBOL_GPL(event_filter_unregister); + +int event_filter_set(const char *name) +{ + struct ev_filter *f; + + f = event_filter_find(name); + if (f == NULL) + return -EINVAL; + + filter_current = f; + + return 0; +} +EXPORT_SYMBOL_GPL(event_filter_set); + +const char *event_filter_get(void) +{ + return filter_current->name; +} + +void event_filter_on_each(void (*func)(struct ev_filter *, void *), + void *data) +{ + struct ev_filter *f, *tmp; + + list_for_each_entry_safe(f, tmp, &filter_list, list) + func(f, data); +} + +int event_filter_init(void) +{ + return event_filter_register(&filter_none); +} + +void event_filter_exit(void) +{ + event_filter_unregister(&filter_none);; +} diff --git a/writer/event_filter.h b/writer/event_filter.h new file mode 100644 index 0000000..3adcaae --- /dev/null +++ b/writer/event_filter.h @@ -0,0 +1,53 @@ +#ifndef _EVENT_FILTER_H +#define _EVENT_FILTER_H + +/* + * SWAP kernel features + * writer/event_filter.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Samsung Electronics, 2013 + * + * 2013 Vyacheslav Cherkashin + * + */ + + +#include + +struct task_struct; + +struct ev_filter { + struct list_head list; + char *name; + int (*filter)(struct task_struct *); +}; + + +int check_event(struct task_struct *task); + +int event_filter_register(struct ev_filter *f); +void event_filter_unregister(struct ev_filter *f); +int event_filter_set(const char *name); +const char *event_filter_get(void); + +void event_filter_on_each(void (*func)(struct ev_filter *, void *), + void *data); + +int event_filter_init(void); +void event_filter_exit(void); + +#endif /* _EVENT_FILTER_H */ diff --git a/writer/swap_writer_module.c b/writer/swap_writer_module.c index 5748d16..9b294a1 100644 --- a/writer/swap_writer_module.c +++ b/writer/swap_writer_module.c @@ -42,6 +42,7 @@ #include "swap_writer_errors.h" #include "kernel_operations.h" #include "debugfs_writer.h" +#include "event_filter.h" enum MSG_ID { @@ -357,6 +358,9 @@ int sample_msg(struct pt_regs *regs) { char *buf, *payload, *buf_end; + if (!check_event(current)) + return 0; + buf = get_current_buf(); payload = pack_basic_msg_fmt(buf, MSG_SAMPLE); buf_end = pack_sample(payload, regs); @@ -503,6 +507,9 @@ int entry_event(const char *fmt, struct pt_regs *regs, char *buf, *payload, *args, *buf_end; int ret; + if (pt == PT_KS && !check_event(current)) + return 0; + buf = get_current_buf(); payload = pack_basic_msg_fmt(buf, MSG_FUNCTION_ENTRY); args = pack_msg_func_entry(payload, fmt, regs, pt, sub_type); @@ -557,6 +564,9 @@ int exit_event(struct pt_regs *regs, unsigned long func_addr) { char *buf, *payload, *buf_end; + if (!check_event(current)) + return 0; + buf = get_current_buf(); payload = pack_basic_msg_fmt(buf, MSG_FUNCTION_EXIT); buf_end = pack_msg_func_exit(payload, regs, func_addr); @@ -609,12 +619,18 @@ static int context_switch(struct pt_regs *regs, enum MSG_ID id) int switch_entry(struct pt_regs *regs) { + if (!check_event(current)) + return 0; + return context_switch(regs, MSG_CONTEXT_SWITCH_ENTRY); } EXPORT_SYMBOL_GPL(switch_entry); int switch_exit(struct pt_regs *regs) { + if (!check_event(current)) + return 0; + return context_switch(regs, MSG_CONTEXT_SWITCH_EXIT); } EXPORT_SYMBOL_GPL(switch_exit); @@ -688,17 +704,25 @@ int raw_msg(char *buf, size_t len) static int __init swap_writer_module_init(void) { - return init_debugfs_writer(); + int ret; + + ret = event_filter_init(); + if (ret) + return ret; + + ret = init_debugfs_writer(); + if (ret) + event_filter_exit(); + + return ret; } static void __exit swap_writer_module_exit(void) { exit_debugfs_writer(); + event_filter_exit(); } - - - module_init(swap_writer_module_init); module_exit(swap_writer_module_exit); -- 2.7.4