]> pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
ftrace: return error on failed modified text.
authorSteven Rostedt <rostedt@goodmis.org>
Thu, 23 Oct 2008 13:32:59 +0000 (09:32 -0400)
committerIngo Molnar <mingo@elte.hu>
Thu, 23 Oct 2008 14:00:13 +0000 (16:00 +0200)
Have the ftrace_modify_code return error values:

  -EFAULT on error of reading the address

  -EINVAL if what is read does not match what it expected

  -EPERM  if the write fails to update after a successful match.

Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
arch/x86/kernel/ftrace.c
include/linux/ftrace.h
kernel/trace/ftrace.c

index 8821ceabf51df44239de2583f0e95bfe40c1d5f9..428291581cb2441e3cab9e5fd9e28a150d6818e5 100644 (file)
@@ -62,7 +62,6 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code,
                   unsigned char *new_code)
 {
        unsigned char replaced[MCOUNT_INSN_SIZE];
-       int ret;
 
        /*
         * Note: Due to modules and __init, code can
@@ -72,15 +71,16 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code,
         * No real locking needed, this code is run through
         * kstop_machine, or before SMP starts.
         */
-       if (__copy_from_user_inatomic(replaced, (char __user *)ip, MCOUNT_INSN_SIZE))
-               return 1;
+       if (__copy_from_user_inatomic(replaced, (char __user *)ip,
+                                     MCOUNT_INSN_SIZE))
+               return -EFAULT;
 
        if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0)
-               return 2;
+               return -EINVAL;
 
-       ret = __copy_to_user_inatomic((char __user *)ip, new_code,
-                                       MCOUNT_INSN_SIZE);
-       WARN_ON_ONCE(ret);
+       if (__copy_to_user_inatomic((char __user *)ip, new_code,
+                                   MCOUNT_INSN_SIZE))
+               return -EPERM;
 
        sync_core();
 
index 0e952958915137dbe1c232756edae0cdb0409659..79fa10cbdcfb686ab47409279815aae75d53fe71 100644 (file)
@@ -72,13 +72,33 @@ extern unsigned char *ftrace_nop_replace(void);
 extern unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr);
 extern int ftrace_dyn_arch_init(void *data);
 extern int ftrace_mcount_set(unsigned long *data);
-extern int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
-                             unsigned char *new_code);
 extern int ftrace_update_ftrace_func(ftrace_func_t func);
 extern void ftrace_caller(void);
 extern void ftrace_call(void);
 extern void mcount_call(void);
 
+/**
+ * ftrace_modify_code - modify code segment
+ * @ip: the address of the code segment
+ * @old_code: the contents of what is expected to be there
+ * @new_code: the code to patch in
+ *
+ * This is a very sensitive operation and great care needs
+ * to be taken by the arch.  The operation should carefully
+ * read the location, check to see if what is read is indeed
+ * what we expect it to be, and then on success of the compare,
+ * it should write to the location.
+ *
+ * Return must be:
+ *  0 on success
+ *  -EFAULT on error reading the location
+ *  -EINVAL on a failed compare of the contents
+ *  -EPERM  on error writing to the location
+ * Any other value will be considered a failure.
+ */
+extern int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
+                             unsigned char *new_code);
+
 extern int skip_trace(unsigned long ip);
 
 extern void ftrace_release(void *start, unsigned long size);
index 1f54a94189fe8f53a5382f7a931e41bd39e57520..b2de8de773560730c93a14f831ba38d4e1e0ba96 100644 (file)
@@ -596,22 +596,22 @@ ftrace_code_disable(struct dyn_ftrace *rec)
 {
        unsigned long ip;
        unsigned char *nop, *call;
-       int failed;
+       int ret;
 
        ip = rec->ip;
 
        nop = ftrace_nop_replace();
        call = ftrace_call_replace(ip, mcount_addr);
 
-       failed = ftrace_modify_code(ip, call, nop);
-       if (failed) {
-               switch (failed) {
-               case 1:
+       ret = ftrace_modify_code(ip, call, nop);
+       if (ret) {
+               switch (ret) {
+               case -EFAULT:
                        WARN_ON_ONCE(1);
                        pr_info("ftrace faulted on modifying ");
                        print_ip_sym(ip);
                        break;
-               case 2:
+               case -EINVAL:
                        WARN_ON_ONCE(1);
                        pr_info("ftrace failed to modify ");
                        print_ip_sym(ip);
@@ -620,6 +620,15 @@ ftrace_code_disable(struct dyn_ftrace *rec)
                        print_ip_ins(" replace: ", nop);
                        printk(KERN_CONT "\n");
                        break;
+               case -EPERM:
+                       WARN_ON_ONCE(1);
+                       pr_info("ftrace faulted on writing ");
+                       print_ip_sym(ip);
+                       break;
+               default:
+                       WARN_ON_ONCE(1);
+                       pr_info("ftrace faulted on unknown error ");
+                       print_ip_sym(ip);
                }
 
                rec->flags |= FTRACE_FL_FAILED;