vt: introduce and use vt_kmsg_redirect() function
[linux-2.6-block.git] / kernel / hw_breakpoint.c
index 03a0773ac2b2c89dabe4ddd7aeb371fec94fb0d1..366eedf949c0a47380af9050463dae76431aa063 100644 (file)
@@ -320,18 +320,40 @@ EXPORT_SYMBOL_GPL(register_user_hw_breakpoint);
  * @triggered: callback to trigger when we hit the breakpoint
  * @tsk: pointer to 'task_struct' of the process to which the address belongs
  */
-struct perf_event *
-modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr)
+int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr)
 {
-       /*
-        * FIXME: do it without unregistering
-        * - We don't want to lose our slot
-        * - If the new bp is incorrect, don't lose the older one
-        */
-       unregister_hw_breakpoint(bp);
+       u64 old_addr = bp->attr.bp_addr;
+       int old_type = bp->attr.bp_type;
+       int old_len = bp->attr.bp_len;
+       int err = 0;
+
+       perf_event_disable(bp);
+
+       bp->attr.bp_addr = attr->bp_addr;
+       bp->attr.bp_type = attr->bp_type;
+       bp->attr.bp_len = attr->bp_len;
+
+       if (attr->disabled)
+               goto end;
 
-       return perf_event_create_kernel_counter(attr, -1, bp->ctx->task->pid,
-                                               bp->overflow_handler);
+       err = arch_validate_hwbkpt_settings(bp, bp->ctx->task);
+       if (!err)
+               perf_event_enable(bp);
+
+       if (err) {
+               bp->attr.bp_addr = old_addr;
+               bp->attr.bp_type = old_type;
+               bp->attr.bp_len = old_len;
+               if (!bp->attr.disabled)
+                       perf_event_enable(bp);
+
+               return err;
+       }
+
+end:
+       bp->attr.disabled = attr->disabled;
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint);