From: Vyacheslav Cherkashin Date: Thu, 27 Feb 2014 12:39:15 +0000 (-0800) Subject: Merge "[REFACTOR] Buffer: move getting next queue element into separate function" X-Git-Tag: Tizen_SDK_2.3~124 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e970dee4cbab29d3973d369a75e25e8b89eb3080;hp=649bcf23f01044eae956e92e6d01811579c80739;p=kernel%2Fswap-modules.git Merge "[REFACTOR] Buffer: move getting next queue element into separate function" --- diff --git a/buffer/buffer_queue.c b/buffer/buffer_queue.c index 6163b4b..8744b21 100644 --- a/buffer/buffer_queue.c +++ b/buffer/buffer_queue.c @@ -123,7 +123,7 @@ int buffer_queue_allocation(size_t subbuffer_size, sync_init(&buffer_busy_sync); /* Memory allocation for queue_busy */ - queue_busy = memory_allocation(sizeof(**queue_busy) * queue_subbuffer_count); + queue_busy = memory_allocation(sizeof(*queue_busy) * queue_subbuffer_count); if (!queue_busy) { result = -E_SB_NO_MEM_QUEUE_BUSY; diff --git a/buffer/swap_buffer_module.c b/buffer/swap_buffer_module.c index 0d228c1..3f3880a 100644 --- a/buffer/swap_buffer_module.c +++ b/buffer/swap_buffer_module.c @@ -69,7 +69,7 @@ static inline int areas_overlap(const void *area1,const void *area2, size_t size int i; for (i = 0; i < size; i++) - if ((area1 + i == area2) || (area1 + i == area2)) + if ((area1 + i == area2) || (area2 + i == area1)) return 1; return 0; diff --git a/driver/device_driver.c b/driver/device_driver.c index 07913d3..af7f9e5 100644 --- a/driver/device_driver.c +++ b/driver/device_driver.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -96,6 +97,32 @@ static struct device *swap_device_device = NULL; /* Reading tasks queue */ static DECLARE_WAIT_QUEUE_HEAD(swap_device_wait); + +static atomic_t flag_wake_up = ATOMIC_INIT(0); + +static void __bottom_wake_up(void) +{ + if (waitqueue_active(&swap_device_wait)) + wake_up_interruptible(&swap_device_wait); +} + +static void bottom_wake_up(struct work_struct *work) +{ + if (atomic_read(&flag_wake_up)) { + atomic_set(&flag_wake_up, 0); + __bottom_wake_up(); + } +} + +static DECLARE_WORK(w_wake_up, bottom_wake_up); + +static void exit_w_wake_up(void) +{ + flush_scheduled_work(); + __bottom_wake_up(); +} + + /* We need this realization of splice_shrink_spd() because of the its desing * frequent changes that I have encountered in custom kernels */ void swap_device_splice_shrink_spd(struct pipe_inode_info *pipe, @@ -192,6 +219,8 @@ init_fail: /* Unregister device TODO Check wether driver is registered */ void swap_device_exit(void) { + exit_w_wake_up(); + splice_to_pipe_p = NULL; splice_grow_spd_p = NULL; @@ -436,7 +465,10 @@ swap_device_splice_read_error: void swap_device_wake_up_process(void) { - wake_up_interruptible(&swap_device_wait); + if (atomic_read(&flag_wake_up) == 0) { + atomic_set(&flag_wake_up, 1); + schedule_work(&w_wake_up); + } } void set_msg_handler(msg_handler_t mh) diff --git a/energy/Kbuild b/energy/Kbuild index 2ea75da..80d23c9 100644 --- a/energy/Kbuild +++ b/energy/Kbuild @@ -32,6 +32,13 @@ ifeq ($(CONFIG_LCD_S6E8AA0), y) endif +# PANEL_S6E8AA0: +ifeq ($(CONFIG_DISPLAY_PANEL_S6E8AA0), y) + swap_energy-y += lcd/s6e8aa0_panel.o + LCD_FUNC_LIST += s6e8aa0_panel +endif + + # MARU: ifeq ($(CONFIG_MARU_BACKLIGHT), y) swap_energy-y += lcd/maru.o diff --git a/energy/lcd/lcd_base.c b/energy/lcd/lcd_base.c index a2521ba..0c9938a 100644 --- a/energy/lcd/lcd_base.c +++ b/energy/lcd/lcd_base.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "lcd_base.h" #include "lcd_debugfs.h" @@ -64,6 +65,11 @@ enum { brt_cnt = 10 }; +enum power_t { + PW_ON, + PW_OFF +}; + struct lcd_priv_data { int min_brt; int max_brt; @@ -72,6 +78,7 @@ struct lcd_priv_data { struct tm_stat *tms_brt; spinlock_t lock_tms; int brt_old; + enum power_t power; u64 min_denom; u64 min_num; @@ -108,6 +115,7 @@ static void *create_lcd_priv(struct lcd_ops *ops, size_t tms_brt_cnt) spin_lock_init(&lcd->lock_tms); lcd->brt_old = brt_no_init; + lcd->power = PW_OFF; lcd->min_denom = 1; lcd->min_num = 1; @@ -140,11 +148,8 @@ static void clean_brightness(struct lcd_ops *ops) spin_unlock(&lcd->lock_tms); } -static void set_brightness(struct lcd_ops *ops, int brt) +static int get_brt_num_of_array(struct lcd_priv_data *lcd, int brt) { - struct lcd_priv_data *lcd = get_lcd_priv(ops); - int n; - if (brt > lcd->max_brt || brt < lcd->min_brt) { printk("LCD energy error: set brightness=%d, " "when brightness[%d..%d]\n", @@ -152,18 +157,80 @@ static void set_brightness(struct lcd_ops *ops, int brt) brt = brt > lcd->max_brt ? lcd->max_brt : lcd->min_brt; } - n = lcd->tms_brt_cnt * (brt - lcd->min_brt) / - (lcd->max_brt - lcd->min_brt + 1); + return lcd->tms_brt_cnt * (brt - lcd->min_brt) / + (lcd->max_brt - lcd->min_brt + 1); +} + +static void set_brightness(struct lcd_ops *ops, int brt) +{ + struct lcd_priv_data *lcd = get_lcd_priv(ops); + int n = get_brt_num_of_array(lcd, brt); spin_lock(&lcd->lock_tms); - if (lcd->brt_old != n) { + + if (lcd->power == PW_ON && lcd->brt_old != n) { u64 time = get_ntime(); if (lcd->brt_old != brt_no_init) tm_stat_update(&lcd->tms_brt[lcd->brt_old], time); tm_stat_set_timestamp(&lcd->tms_brt[n], time); - lcd->brt_old = n; } + lcd->brt_old = n; + + spin_unlock(&lcd->lock_tms); +} + +static void set_power_on_set_brt(struct lcd_priv_data *lcd) +{ + if (lcd->brt_old != brt_no_init) { + u64 time = get_ntime(); + tm_stat_set_timestamp(&lcd->tms_brt[lcd->brt_old], time); + } +} + +static void set_power_on(struct lcd_priv_data *lcd) +{ + if (lcd->power == PW_OFF) + set_power_on_set_brt(lcd); + + lcd->power = PW_ON; +} + +static void set_power_off_update_brt(struct lcd_priv_data *lcd) +{ + if (lcd->brt_old != brt_no_init) { + u64 time = get_ntime(); + tm_stat_update(&lcd->tms_brt[lcd->brt_old], time); + lcd->brt_old = brt_no_init; + } +} + +static void set_power_off(struct lcd_priv_data *lcd) +{ + if (lcd->power == PW_ON) + set_power_off_update_brt(lcd); + + lcd->power = PW_OFF; +} + +static void set_power(struct lcd_ops *ops, int val) +{ + struct lcd_priv_data *lcd = get_lcd_priv(ops); + + spin_lock(&lcd->lock_tms); + + switch (val) { + case FB_BLANK_UNBLANK: + set_power_on(lcd); + break; + case FB_BLANK_POWERDOWN: + set_power_off(lcd); + break; + default: + printk("LCD energy error: set power=%d\n", val); + break; + } + spin_unlock(&lcd->lock_tms); } @@ -174,7 +241,11 @@ static int func_notifier_lcd(struct lcd_ops *ops, enum lcd_action_type action, case LAT_BRIGHTNESS: set_brightness(ops, (int)data); break; + case LAT_POWER: + set_power(ops, (int)data); + break; default: + printk("LCD energy error: action=%d\n", action); return -EINVAL; } @@ -194,11 +265,14 @@ void get_lcd_array_time(struct lcd_ops *ops, u64 *array_time) int i; spin_lock(&lcd->lock_tms); - for (i = 0; i < lcd->tms_brt_cnt; ++i) { + for (i = 0; i < lcd->tms_brt_cnt; ++i) array_time[i] = tm_stat_running(&lcd->tms_brt[i]); - if (i == lcd->brt_old) - array_time[i] += get_ntime() - - tm_stat_timestamp(&lcd->tms_brt[i]); + + if (lcd->power == PW_ON && lcd->brt_old != brt_no_init) { + int old = lcd->brt_old; + struct tm_stat *tm = &lcd->tms_brt[old]; + + array_time[old] += get_ntime() - tm_stat_timestamp(tm); } spin_unlock(&lcd->lock_tms); } @@ -330,6 +404,7 @@ int lcd_set_energy(void) } set_brightness(ops, ops->get(ops, LPD_BRIGHTNESS)); + set_power(ops, ops->get(ops, LPD_POWER)); stat_lcd_ops[i] |= SLO_SET; ++count; diff --git a/energy/lcd/lcd_base.h b/energy/lcd/lcd_base.h index 5115cb3..3e210f6 100644 --- a/energy/lcd/lcd_base.h +++ b/energy/lcd/lcd_base.h @@ -31,13 +31,16 @@ enum lcd_action_type { - LAT_BRIGHTNESS + LAT_BRIGHTNESS, + LAT_POWER }; enum lcd_parameter_type { LPD_MIN_BRIGHTNESS, LPD_MAX_BRIGHTNESS, - LPD_BRIGHTNESS + LPD_BRIGHTNESS, + + LPD_POWER }; struct lcd_ops; diff --git a/energy/lcd/maru.c b/energy/lcd/maru.c index 7adb170..fb75f88 100644 --- a/energy/lcd/maru.c +++ b/energy/lcd/maru.c @@ -32,11 +32,13 @@ static const char path_backlight[] = "/sys/class/backlight/emulator/brightness"; static const char path_backlight_min[] = "/sys/class/backlight/emulator/min_brightness"; static const char path_backlight_max[] = "/sys/class/backlight/emulator/max_brightness"; +static const char path_power[] = "/sys/class/lcd/emulator/lcd_power"; static const char *all_path[] = { path_backlight, path_backlight_min, - path_backlight_max + path_backlight_max, + path_power }; enum { @@ -68,9 +70,11 @@ static unsigned long maru_get_parameter(struct lcd_ops *ops, return read_val(path_backlight_max); case LPD_BRIGHTNESS: return read_val(path_backlight); + case LPD_POWER: + return read_val(path_power); + default: + return -EINVAL; } - - return -EINVAL; } diff --git a/energy/lcd/s6e8aa0.c b/energy/lcd/s6e8aa0.c index e90a4e8..b607557 100644 --- a/energy/lcd/s6e8aa0.c +++ b/energy/lcd/s6e8aa0.c @@ -5,11 +5,13 @@ static const char path_backlight[] = "/sys/class/backlight/s6e8aa0-bl/brightness"; static const char path_backlight_min[] = "/sys/class/backlight/s6e8aa0-bl/min_brightness"; static const char path_backlight_max[] = "/sys/class/backlight/s6e8aa0-bl/max_brightness"; +static const char path_power[] = "/sys/class/lcd/s6e8aa0/lcd_power"; static const char *all_path[] = { path_backlight, path_backlight_min, - path_backlight_max + path_backlight_max, + path_power }; enum { @@ -42,48 +44,19 @@ static unsigned long s6e8aa0_get_parameter(struct lcd_ops *ops, return read_val(path_backlight_max); case LPD_BRIGHTNESS: return read_val(path_backlight); + case LPD_POWER: + return read_val(path_power); + default: + return -EINVAL; } - - return -EINVAL; } - - -#if 0 /* is not supported */ -/* ============================================================================ - * === POWER === - * ============================================================================ - */ -static int get_power(void) -{ - const char *power_path = "/sys/class/lcd/s6e8aa0/lcd_power"; - - return read_val(power_path); -} - static int entry_handler_set_power(struct kretprobe_instance *ri, - struct pt_regs *regs) -{ - int *power = (int *)ri->data; - - *power = (int)regs->ARM_r1; - - return 0; -} - + struct pt_regs *regs); static int ret_handler_set_power(struct kretprobe_instance *ri, - struct pt_regs *regs) -{ - int ret = regs_return_value(regs); - int *power = (int *)ri->data; - - if (!ret && ops_s && ops_s->set_power) - ops_s->set_power(*power); - - return 0; -} + struct pt_regs *regs); static struct kretprobe set_power_krp = { .kp.symbol_name = "s6e8aa0_set_power", @@ -91,8 +64,6 @@ static struct kretprobe set_power_krp = { .handler = ret_handler_set_power, .data_size = sizeof(int) }; -#endif - static int entry_handler_set_backlight(struct kretprobe_instance *ri, @@ -109,12 +80,24 @@ static struct kretprobe set_backlight_krp = { int s6e8aa0_set(struct lcd_ops *ops) { - return dbi_register_kretprobe(&set_backlight_krp); + int ret; + + ret = dbi_register_kretprobe(&set_power_krp); + if (ret) + return ret; + + ret = dbi_register_kretprobe(&set_backlight_krp); + if (ret) + dbi_unregister_kretprobe(&set_power_krp); + + return ret; } int s6e8aa0_unset(struct lcd_ops *ops) { dbi_unregister_kretprobe(&set_backlight_krp); + dbi_unregister_kretprobe(&set_power_krp); + return 0; } @@ -136,6 +119,36 @@ struct lcd_ops *LCD_MAKE_FNAME(s6e8aa0)(void) /* ============================================================================ + * === POWER === + * ============================================================================ + */ +static int entry_handler_set_power(struct kretprobe_instance *ri, + struct pt_regs *regs) +{ + int *power = (int *)ri->data; + + *power = (int)swap_get_karg(regs, 1); + + return 0; +} + +static int ret_handler_set_power(struct kretprobe_instance *ri, + struct pt_regs *regs) +{ + int ret = regs_return_value(regs); + int *power = (int *)ri->data; + + if (!ret && s6e8aa0_ops.notifier) + s6e8aa0_ops.notifier(&s6e8aa0_ops, LAT_POWER, (void *)*power); + + return 0; +} + + + + + +/* ============================================================================ * === BACKLIGHT === * ============================================================================ */ diff --git a/energy/lcd/s6e8aa0_panel.c b/energy/lcd/s6e8aa0_panel.c new file mode 100644 index 0000000..1b5abfa --- /dev/null +++ b/energy/lcd/s6e8aa0_panel.c @@ -0,0 +1,178 @@ +#include +#include +#include "lcd_base.h" + + +static const char path_backlight[] = "/sys/class/backlight/s6e8aa0-bl/brightness"; +static const char path_backlight_max[] = "/sys/class/backlight/s6e8aa0-bl/max_brightness"; +static const char path_power[] = "/sys/class/lcd/s6e8aa0/lcd_power"; + +static const char *all_path[] = { + path_backlight, + path_backlight_max, + path_power +}; + +enum { + all_path_cnt = sizeof(all_path) / sizeof(char *) +}; + + + +static int s6e8aa0_check(struct lcd_ops *ops) +{ + int i; + + for (i = 0; i < all_path_cnt; ++i) { + int ret = read_val(all_path[i]); + + if (IS_ERR_VALUE(ret)) + return 0; + } + + return 1; +} + +static unsigned long s6e8aa0_get_parameter(struct lcd_ops *ops, + enum lcd_parameter_type type) +{ + switch (type) { + case LPD_MIN_BRIGHTNESS: + return 0; + case LPD_MAX_BRIGHTNESS: + return read_val(path_backlight_max); + case LPD_BRIGHTNESS: + return read_val(path_backlight); + case LPD_POWER: + return read_val(path_power); + } + + return -EINVAL; +} + + + +static int entry_handler_set_power(struct kretprobe_instance *ri, + struct pt_regs *regs); +static int ret_handler_set_power(struct kretprobe_instance *ri, + struct pt_regs *regs); + +static struct kretprobe set_power_krp = { + .kp.symbol_name = "s6e8aa0_set_power", + .entry_handler = entry_handler_set_power, + .handler = ret_handler_set_power, + .data_size = sizeof(int) +}; + + +static int entry_handler_set_backlight(struct kretprobe_instance *ri, + struct pt_regs *regs); +static int ret_handler_set_backlight(struct kretprobe_instance *ri, + struct pt_regs *regs); + +static struct kretprobe set_backlight_krp = { + .kp.symbol_name = "s6e8aa0_update_status", + .entry_handler = entry_handler_set_backlight, + .handler = ret_handler_set_backlight, + .data_size = sizeof(int) +}; + +int s6e8aa0_set(struct lcd_ops *ops) +{ + int ret; + + ret = dbi_register_kretprobe(&set_power_krp); + if (ret) + return ret; + + ret = dbi_register_kretprobe(&set_backlight_krp); + if (ret) + dbi_unregister_kretprobe(&set_power_krp); + + return ret; +} + +int s6e8aa0_unset(struct lcd_ops *ops) +{ + dbi_unregister_kretprobe(&set_backlight_krp); + dbi_unregister_kretprobe(&set_power_krp); + + return 0; +} + +static struct lcd_ops s6e8aa0_ops = { + .name = "s6e8aa0_panel", + .check = s6e8aa0_check, + .set = s6e8aa0_set, + .unset = s6e8aa0_unset, + .get = s6e8aa0_get_parameter +}; + +struct lcd_ops *LCD_MAKE_FNAME(s6e8aa0_panel)(void) +{ + return &s6e8aa0_ops; +} + + + + + +/* ============================================================================ + * === POWER === + * ============================================================================ + */ +static int entry_handler_set_power(struct kretprobe_instance *ri, + struct pt_regs *regs) +{ + int *power = (int *)ri->data; + + *power = (int)swap_get_karg(regs, 1); + + return 0; +} + +static int ret_handler_set_power(struct kretprobe_instance *ri, + struct pt_regs *regs) +{ + int ret = regs_return_value(regs); + int *power = (int *)ri->data; + + if (!ret && s6e8aa0_ops.notifier) + s6e8aa0_ops.notifier(&s6e8aa0_ops, LAT_POWER, + (void *)*power); + + return 0; +} + + + + + +/* ============================================================================ + * === BACKLIGHT === + * ============================================================================ + */ +static int entry_handler_set_backlight(struct kretprobe_instance *ri, + struct pt_regs *regs) +{ + int *brightness = (int *)ri->data; + struct backlight_device *bd; + + bd = (struct backlight_device *)swap_get_karg(regs, 0); + *brightness = bd->props.brightness; + + return 0; +} + +static int ret_handler_set_backlight(struct kretprobe_instance *ri, + struct pt_regs *regs) +{ + int ret = regs_return_value(regs); + int *brightness = (int *)ri->data; + + if (!ret && s6e8aa0_ops.notifier) + s6e8aa0_ops.notifier(&s6e8aa0_ops, LAT_BRIGHTNESS, + (void *)*brightness); + + return 0; +} diff --git a/kprobe/arch/asm-arm/dbi_kprobes.c b/kprobe/arch/asm-arm/dbi_kprobes.c index f5ccf4b..92ede61 100644 --- a/kprobe/arch/asm-arm/dbi_kprobes.c +++ b/kprobe/arch/asm-arm/dbi_kprobes.c @@ -163,7 +163,7 @@ int arch_prepare_kprobe(struct kprobe *p, struct slot_manager *sm) return -ENOMEM; memcpy(insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); - ainsn.insn_arm = ainsn.insn = insn; + ainsn.insn = insn; ret = arch_check_insn_arm(insn[0]); if (!ret) { p->opcode = *p->addr; diff --git a/kprobe/arch/asm-arm/dbi_kprobes.h b/kprobe/arch/asm-arm/dbi_kprobes.h index 08deda2..2e2c85d 100644 --- a/kprobe/arch/asm-arm/dbi_kprobes.h +++ b/kprobe/arch/asm-arm/dbi_kprobes.h @@ -468,8 +468,6 @@ struct kprobe_ctlblk { struct arch_specific_insn { /* copy of the original instruction */ kprobe_opcode_t *insn; - kprobe_opcode_t *insn_arm; - kprobe_opcode_t *insn_thumb; }; typedef kprobe_opcode_t (*entry_point_t) (unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); diff --git a/kprobe/arch/asm-x86/dbi_kprobes.c b/kprobe/arch/asm-x86/dbi_kprobes.c index a6c8c17..38ce8b0 100644 --- a/kprobe/arch/asm-x86/dbi_kprobes.c +++ b/kprobe/arch/asm-x86/dbi_kprobes.c @@ -745,7 +745,7 @@ int kprobe_exceptions_notify (struct notifier_block *self, unsigned long val, vo DBPRINTF ("val = %ld, data = 0x%X", val, (unsigned int) data); - if (args->regs && user_mode_vm(args->regs)) + if (args->regs == NULL || user_mode_vm(args->regs)) return ret; DBPRINTF ("switch (val) %lu %d %d", val, DIE_INT3, DIE_TRAP); diff --git a/kprobe/dbi_kprobes.c b/kprobe/dbi_kprobes.c index 40ee61b..7a9febf 100644 --- a/kprobe/dbi_kprobes.c +++ b/kprobe/dbi_kprobes.c @@ -75,8 +75,7 @@ struct slot_manager sm; DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; static DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); -DEFINE_SPINLOCK(kretprobe_lock); /* Protects kretprobe_inst_table */ -EXPORT_SYMBOL_GPL(kretprobe_lock); +static DEFINE_SPINLOCK(kretprobe_lock); /* Protects kretprobe_inst_table */ static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL; struct hlist_head kprobe_table[KPROBE_TABLE_SIZE]; @@ -504,8 +503,11 @@ int dbi_register_kprobe(struct kprobe *p) * and add it to the address. That way the addr * field can either be global or relative to a symbol. */ - if (p->symbol_name) + if (p->symbol_name) { + if (p->addr) + return -EINVAL; p->addr = (kprobe_opcode_t *)swap_ksyms(p->symbol_name); + } if (!p->addr) return -EINVAL; @@ -543,64 +545,54 @@ out: return ret; } -void dbi_unregister_kprobe(struct kprobe *p) +static void dbi_unregister_valid_kprobe(struct kprobe *p, struct kprobe *old_p) { - struct kprobe *old_p, *list_p; - int cleanup_p; - - old_p = get_kprobe(p->addr); - DBPRINTF ("dbi_unregister_kprobe p=%p old_p=%p", p, old_p); - if (unlikely (!old_p)) - return; + struct kprobe *list_p; - if (p != old_p) { - list_for_each_entry_rcu(list_p, &old_p->list, list) - if (list_p == p) - /* kprobe p is a valid probe */ - goto valid_p; - return; - } - -valid_p: - DBPRINTF ("dbi_unregister_kprobe valid_p"); if ((old_p == p) || ((old_p->pre_handler == aggr_pre_handler) && (p->list.next == &old_p->list) && (p->list.prev == &old_p->list))) { /* Only probe on the hash list */ arch_disarm_kprobe(p); hlist_del_rcu(&old_p->hlist); - cleanup_p = 1; - } else { - list_del_rcu(&p->list); - cleanup_p = 0; - } - DBPRINTF ("dbi_unregister_kprobe cleanup_p=%d", cleanup_p); - if (cleanup_p) { - if (p != old_p) { - list_del_rcu(&p->list); + if (p != old_p) kfree(old_p); - } - - if (!in_atomic()) { - synchronize_sched(); - } - - remove_kprobe(p); + /* Synchronize and remove probe in bottom */ } else { + list_del_rcu(&p->list); + if (p->break_handler) old_p->break_handler = NULL; if (p->post_handler) { - list_for_each_entry_rcu(list_p, &old_p->list, list) { - if (list_p->post_handler) { - cleanup_p = 2; - break; - } - } - - if (cleanup_p == 0) - old_p->post_handler = NULL; + list_for_each_entry_rcu(list_p, &old_p->list, list) + if (list_p->post_handler) + return; + + old_p->post_handler = NULL; } } + /* Set NULL addr for reusability if symbol_name is used */ + if (p->symbol_name) + p->addr = NULL; +} + +void dbi_unregister_kprobe(struct kprobe *kp) +{ + struct kprobe *old_p, *list_p; + + old_p = get_kprobe(kp->addr); + if (unlikely (!old_p)) + return; + + if (kp != old_p) { + list_for_each_entry_rcu(list_p, &old_p->list, list) + if (list_p == kp) + /* kprobe p is a valid probe */ + dbi_unregister_valid_kprobe(kp, old_p); + return; + } + + dbi_unregister_valid_kprobe(kp, old_p); } int dbi_register_jprobe(struct jprobe *jp) @@ -832,15 +824,11 @@ static int dbi_disarm_krp_inst(struct kretprobe_instance *ri); static void dbi_unregister_kretprobe_top(struct kretprobe *rp) { - unsigned long flags; struct kretprobe_instance *ri; DECLARE_NODE_PTR_FOR_HLIST(node); dbi_unregister_kprobe(&rp->kp); - /* No race here */ - spin_lock_irqsave(&kretprobe_lock, flags); - swap_hlist_for_each_entry(ri, node, &rp->used_instances, uflist) { if (!dbi_disarm_krp_inst(ri)) { printk("%s (%d/%d): cannot disarm krp instance (%08lx)\n", @@ -848,7 +836,6 @@ static void dbi_unregister_kretprobe_top(struct kretprobe *rp) (unsigned long)rp->kp.addr); } } - spin_unlock_irqrestore(&kretprobe_lock, flags); } static void dbi_unregister_kretprobe_bottom(struct kretprobe *rp) @@ -856,18 +843,41 @@ static void dbi_unregister_kretprobe_bottom(struct kretprobe *rp) unsigned long flags; struct kretprobe_instance *ri; + if (list_empty(&rp->kp.list)) + remove_kprobe(&rp->kp); + spin_lock_irqsave(&kretprobe_lock, flags); + while ((ri = get_used_rp_inst(rp)) != NULL) { recycle_rp_inst(ri); } - spin_unlock_irqrestore(&kretprobe_lock, flags); free_rp_inst(rp); + + spin_unlock_irqrestore(&kretprobe_lock, flags); +} + +void dbi_unregister_kretprobes(struct kretprobe **rpp, size_t size) +{ + size_t i; + unsigned long flags; + + spin_lock_irqsave(&kretprobe_lock, flags); + + for (i = 0; i < size; i++) + dbi_unregister_kretprobe_top(rpp[i]); + + spin_unlock_irqrestore(&kretprobe_lock, flags); + + if (!in_atomic()) + synchronize_sched(); + + for (i = 0; i < size; i++) + dbi_unregister_kretprobe_bottom(rpp[i]); } void dbi_unregister_kretprobe(struct kretprobe *rp) { - dbi_unregister_kretprobe_top(rp); - dbi_unregister_kretprobe_bottom(rp); + dbi_unregister_kretprobes(&rp, 1); } struct kretprobe *clone_kretprobe(struct kretprobe *rp) @@ -1037,6 +1047,7 @@ EXPORT_SYMBOL_GPL(dbi_register_jprobe); EXPORT_SYMBOL_GPL(dbi_unregister_jprobe); EXPORT_SYMBOL_GPL(dbi_jprobe_return); EXPORT_SYMBOL_GPL(dbi_register_kretprobe); +EXPORT_SYMBOL_GPL(dbi_unregister_kretprobes); EXPORT_SYMBOL_GPL(dbi_unregister_kretprobe); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/kprobe/dbi_kprobes.h b/kprobe/dbi_kprobes.h index 9b187aa..7c6a479 100644 --- a/kprobe/dbi_kprobes.h +++ b/kprobe/dbi_kprobes.h @@ -254,6 +254,7 @@ struct kretprobe_instance * get_used_rp_inst (struct kretprobe *rp); int alloc_nodes_kretprobe(struct kretprobe *rp); int dbi_register_kretprobe (struct kretprobe *rp); void dbi_unregister_kretprobe (struct kretprobe *rp); +void dbi_unregister_kretprobes(struct kretprobe **rpp, size_t size); void kretprobe_assert (struct kretprobe_instance *ri, unsigned long orig_ret_address, unsigned long trampoline_address); @@ -274,7 +275,6 @@ void set_normalized_timeval (struct timeval *tv, time_t sec, suseconds_t usec); #endif extern DEFINE_PER_CPU (struct kprobe *, current_kprobe); -extern spinlock_t kretprobe_lock; extern struct hlist_head kprobe_table[KPROBE_TABLE_SIZE]; //extern struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; extern atomic_t kprobe_count; diff --git a/ks_features/ks_features.c b/ks_features/ks_features.c index 4ce55de..8af0d36 100644 --- a/ks_features/ks_features.c +++ b/ks_features/ks_features.c @@ -24,6 +24,8 @@ #include +#include + #include #include #include @@ -229,6 +231,7 @@ static int register_syscall(size_t id) return ret; } + static int unregister_syscall(size_t id) { printk("unregister_syscall: %s\n", get_sys_name(id)); @@ -241,6 +244,42 @@ static int unregister_syscall(size_t id) return 0; } +static int unregister_multiple_syscalls(size_t *id_p, size_t cnt) +{ + struct kretprobe **rpp; + const size_t end = ((size_t) 0) - 1; + size_t i = 0, id; + int ret = 0; + + if (cnt == 1) + return unregister_syscall(id_p[0]); + + --cnt; + + rpp = kmalloc(GFP_KERNEL, sizeof(&(((struct ks_probe *) 0)->rp)) * cnt); + if (rpp == NULL) { + for (; cnt != end; --cnt) { + ret = unregister_syscall(id_p[cnt]); + if (ret) + return ret; + } + return ret; + } + + for (; cnt != end; --cnt) { + id = id_p[cnt]; + if (ksp[id].rp.kp.addr != NULL) { + rpp[i] = &ksp[id].rp; + ++i; + } + } + + dbi_unregister_kretprobes(rpp, i); + kfree(rpp); + + return 0; +} + static void set_pst(struct feature *f, size_t id) { ksp[id].sub_type |= f->sub_type; @@ -254,30 +293,45 @@ static void unset_pst(struct feature *f, size_t id) static void do_uninstall_features(struct feature *f, size_t i) { int ret; + size_t *id_p; size_t id; + size_t cnt = 0; const size_t end = ((size_t) 0) - 1; + id_p = kmalloc(GFP_KERNEL, sizeof(id) * (i + 1)); + /* NULL check is below in loop */ + for (; i != end; --i) { id = f->feature_list[i]; if (get_counter(id) == 0) { printk("syscall %s not installed\n", get_sys_name(id)); + kfree(id_p); BUG(); } dec_counter(id); if (get_counter(id) == 0) { - ret = unregister_syscall(id); - if (ret) - printk("syscall %s uninstall error, ret=%d\n", - get_sys_name(id), ret); - + if (id_p != NULL) { + id_p[cnt] = id; + ++cnt; + } else { + ret = unregister_syscall(id); + if (ret) + printk("syscall %s uninstall error, ret=%d\n", + get_sys_name(id), ret); + } } unset_pst(f, id); } + + if (id_p != NULL) { + unregister_multiple_syscalls(id_p, cnt); + kfree(id_p); + } } static int do_install_features(struct feature *f) @@ -337,12 +391,11 @@ static int uninstall_features(struct feature *f) ret = -EINVAL; goto unlock; } - do_uninstall_features(f, f->cnt - 1); - f->enable = 0; unlock: mutex_unlock(&mutex_features); + return ret; } diff --git a/parser/msg_buf.c b/parser/msg_buf.c index 031215e..3520874 100644 --- a/parser/msg_buf.c +++ b/parser/msg_buf.c @@ -114,19 +114,22 @@ int get_u64(struct msg_buf *mb, u64 *val) int get_string(struct msg_buf *mb, char **str) { size_t len, len_max; + enum { min_len_str = 1 }; - len_max = mb->end - mb->ptr - 1; - if(len_max < 0) + if (cmp_mb(mb, min_len_str) < 0) return -EINVAL; - len = strlen(mb->ptr) + 1; + len_max = remained_mb(mb) - 1; + len = strnlen(mb->ptr, len_max); - *str = kmalloc(len, GFP_KERNEL); + *str = kmalloc(len + 1, GFP_KERNEL); if (*str == NULL) return -ENOMEM; memcpy(*str, mb->ptr, len); - mb->ptr += len; + (*str)[len] = '\0'; + + mb->ptr += len + 1; print_parse_debug("str->'%s'\n", *str); return 0; diff --git a/parser/msg_parser.c b/parser/msg_parser.c index 3335732..394aae2 100644 --- a/parser/msg_parser.c +++ b/parser/msg_parser.c @@ -93,15 +93,20 @@ struct app_info_data *create_app_info(struct msg_buf *mb) switch (app_type) { case AT_TIZEN_NATIVE_APP: + case AT_TIZEN_WEB_APP: case AT_COMMON_EXEC: ai->tgid = 0; break; case AT_PID: { - u32 tgid; - ret = str_to_u32(ta_id, &tgid); - if (ret) { - print_err("converting string to PID, str='%s'\n", ta_id); - goto free_ai; + u32 tgid = 0; + + if (*ta_id != '\0') { + ret = str_to_u32(ta_id, &tgid); + if (ret) { + print_err("converting string to PID, " + "str='%s'\n", ta_id); + goto free_ai; + } } ai->tgid = tgid; @@ -285,12 +290,12 @@ struct lib_inst_data *create_lib_inst_data(struct msg_buf *mb) print_parse_debug("func count:"); if (get_u32(mb, &cnt)) { print_err("failed to read count of functions\n"); - return NULL; + goto free_path; } if (remained_mb(mb) / MIN_SIZE_FUNC_INST < cnt) { print_err("to match count of functions(%u)\n", cnt); - return NULL; + goto free_path; } li = kmalloc(sizeof(*li), GFP_KERNEL); diff --git a/parser/msg_parser.h b/parser/msg_parser.h index 6543bb1..55751ac 100644 --- a/parser/msg_parser.h +++ b/parser/msg_parser.h @@ -33,7 +33,8 @@ struct msg_buf; enum APP_TYPE { AT_TIZEN_NATIVE_APP = 0x01, AT_PID = 0x02, - AT_COMMON_EXEC = 0x03 + AT_COMMON_EXEC = 0x03, + AT_TIZEN_WEB_APP = 0x04 }; enum { diff --git a/parser/swap_msg_parser.c b/parser/swap_msg_parser.c index 23127fa..e374bf6 100644 --- a/parser/swap_msg_parser.c +++ b/parser/swap_msg_parser.c @@ -56,12 +56,18 @@ static int msg_handler(void __user *msg) struct msg_buf mb; void __user *payload; struct basic_msg_fmt bmf; + enum { size_max = 128 * 1024 * 1024 }; ret = copy_from_user(&bmf, (void*)msg, sizeof(bmf)); if (ret) return ret; size = bmf.len; + if (size >= size_max) { + printk("%s: too large message, size=%u\n", __func__, size); + return -ENOMEM; + } + ret = init_mb(&mb, size); if (ret) return ret; diff --git a/parser/us_inst.c b/parser/us_inst.c index e402277..aa0489e 100644 --- a/parser/us_inst.c +++ b/parser/us_inst.c @@ -114,10 +114,15 @@ static int get_pfg_by_app_info(struct app_info_data *app_info, struct pf_group * switch (app_info->app_type) { case AT_PID: + if (app_info->tgid == 0) + goto pf_dentry; + *pfg = get_pf_group_by_tgid(app_info->tgid, dentry); break; case AT_TIZEN_NATIVE_APP: + case AT_TIZEN_WEB_APP: case AT_COMMON_EXEC: + pf_dentry: *pfg = get_pf_group_by_dentry(dentry, dentry); break; default: diff --git a/uprobe/arch/asm-x86/swap_uprobes.c b/uprobe/arch/asm-x86/swap_uprobes.c index 0d09c77..2ec59ac 100644 --- a/uprobe/arch/asm-x86/swap_uprobes.c +++ b/uprobe/arch/asm-x86/swap_uprobes.c @@ -375,7 +375,7 @@ static int uprobe_exceptions_notify(struct notifier_block *self, unsigned long v struct die_args *args = (struct die_args *)data; int ret = NOTIFY_DONE; - if (args->regs && !user_mode_vm(args->regs)) + if (args->regs == NULL || !user_mode_vm(args->regs)) return ret; switch (val) { diff --git a/us_manager/us_manager_common.h b/us_manager/us_manager_common.h index 7febc1b..d888b26 100644 --- a/us_manager/us_manager_common.h +++ b/us_manager/us_manager_common.h @@ -32,11 +32,13 @@ static inline unsigned long swap_do_mmap(struct file *filp, unsigned long addr, unsigned long flag, unsigned long offset) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) unsigned long populate; return do_mmap_pgoff(filp, addr, len, prot, flag, offset, &populate); -#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) */ +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) + return do_mmap_pgoff(filp, addr, len, prot, flag, offset); +#else return do_mmap(filp, addr, len, prot, flag, offset); #endif }