Merge tag 'trace-v4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 30 Oct 2018 16:49:56 +0000 (09:49 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 30 Oct 2018 16:49:56 +0000 (09:49 -0700)
Pull tracing updates from Steven Rostedt:
 "The biggest change here is the updates to kprobes

  Back in January I posted patches to create function based events.
  These were the events that you suggested I make to allow developers to
  easily create events in code where no trace event exists. After
  posting those changes for review, it was suggested that we implement
  this instead with kprobes.

  The problem with kprobes is that the interface is too complex and
  needs to be simplified. Masami Hiramatsu posted patches in March and
  I've been playing with them a bit. There's been a bit of clean up in
  the kprobe code that was inspired by the function based event patches,
  and a couple of enhancements to the kprobe event interface.

   - If the arch supports it (we added support for x86), you can place a
     kprobe event at the start of a function and use $arg1, $arg2, etc
     to reference the arguments of a function. (Before you needed to
     know what register or where on the stack the argument was).

   - The second is a way to see array of events. For example, if you
     reference a mac address, you can add:

echo 'p:mac ip_rcv perm_addr=+574($arg2):x8[6]' > kprobe_events

     And this will produce:

mac: (ip_rcv+0x0/0x140) perm_addr={0x52,0x54,0x0,0xc0,0x76,0xec}

  Other changes include

   - Exporting trace_dump_stack to modules

   - Have the stack tracer trace the entire stack (stop trying to remove
     tracing itself, as we keep removing too much).

   - Added support for SDT in uprobes"

[ SDT - "Statically Defined Tracing" are userspace markers for tracing.
  Let's not use random TLA's in explanations unless they are fairly
  well-established as generic (at least for kernel people) - Linus ]

* tag 'trace-v4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: (24 commits)
  tracing: Have stack tracer trace full stack
  tracing: Export trace_dump_stack to modules
  tracing: probeevent: Fix uninitialized used of offset in parse args
  tracing/kprobes: Allow kprobe-events to record module symbol
  tracing/kprobes: Check the probe on unloaded module correctly
  tracing/uprobes: Fix to return -EFAULT if copy_from_user failed
  tracing: probeevent: Add $argN for accessing function args
  x86: ptrace: Add function argument access API
  tracing: probeevent: Add array type support
  tracing: probeevent: Add symbol type
  tracing: probeevent: Unify fetch_insn processing common part
  tracing: probeevent: Append traceprobe_ for exported function
  tracing: probeevent: Return consumed bytes of dynamic area
  tracing: probeevent: Unify fetch type tables
  tracing: probeevent: Introduce new argument fetching code
  tracing: probeevent: Remove NOKPROBE_SYMBOL from print functions
  tracing: probeevent: Cleanup argument field definition
  tracing: probeevent: Cleanup print argument functions
  trace_uprobe: support reference counter in fd-based uprobe
  perf probe: Support SDT markers having reference counter (semaphore)
  ...

1  2 
arch/Kconfig
arch/x86/Kconfig
arch/x86/include/asm/ptrace.h
kernel/events/core.c
kernel/events/uprobes.c

diff --combined arch/Kconfig
@@@ -290,6 -290,13 +290,13 @@@ config HAVE_RSE
          This symbol should be selected by an architecture if it
          supports an implementation of restartable sequences.
  
+ config HAVE_FUNCTION_ARG_ACCESS_API
+       bool
+       help
+         This symbol should be selected by an architecure if it supports
+         the API needed to access function arguments from pt_regs,
+         declared in asm/ptrace.h
  config HAVE_CLK
        bool
        help
@@@ -359,9 -366,6 +366,9 @@@ config HAVE_PERF_USER_STACK_DUM
  config HAVE_ARCH_JUMP_LABEL
        bool
  
 +config HAVE_ARCH_JUMP_LABEL_RELATIVE
 +      bool
 +
  config HAVE_RCU_TABLE_FREE
        bool
  
diff --combined arch/x86/Kconfig
@@@ -48,7 -48,6 +48,7 @@@ config X8
        select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI
        select ANON_INODES
        select ARCH_CLOCKSOURCE_DATA
 +      select ARCH_CLOCKSOURCE_INIT
        select ARCH_DISCARD_MEMBLOCK
        select ARCH_HAS_ACPI_TABLE_UPGRADE      if ACPI
        select ARCH_HAS_DEBUG_VIRTUAL
        select HAVE_ARCH_AUDITSYSCALL
        select HAVE_ARCH_HUGE_VMAP              if X86_64 || X86_PAE
        select HAVE_ARCH_JUMP_LABEL
 +      select HAVE_ARCH_JUMP_LABEL_RELATIVE
        select HAVE_ARCH_KASAN                  if X86_64
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_MMAP_RND_BITS          if MMU
        select HAVE_RCU_TABLE_INVALIDATE        if HAVE_RCU_TABLE_FREE
        select HAVE_REGS_AND_STACK_ACCESS_API
        select HAVE_RELIABLE_STACKTRACE         if X86_64 && (UNWINDER_FRAME_POINTER || UNWINDER_ORC) && STACK_VALIDATION
+       select HAVE_FUNCTION_ARG_ACCESS_API
        select HAVE_STACKPROTECTOR              if CC_HAS_SANE_STACKPROTECTOR
        select HAVE_STACK_VALIDATION            if X86_64
        select HAVE_RSEQ
@@@ -449,6 -448,7 +450,6 @@@ config RETPOLIN
  
  config INTEL_RDT
        bool "Intel Resource Director Technology support"
 -      default n
        depends on X86 && CPU_SUP_INTEL
        select KERNFS
        help
@@@ -524,7 -524,6 +525,7 @@@ config X86_VSM
        bool "ScaleMP vSMP"
        select HYPERVISOR_GUEST
        select PARAVIRT
 +      select PARAVIRT_XXL
        depends on X86_64 && PCI
        depends on X86_EXTENDED_PLATFORM
        depends on SMP
@@@ -703,6 -702,7 +704,6 @@@ config STA2X1
        select SWIOTLB
        select MFD_STA2X11
        select GPIOLIB
 -      default n
        ---help---
          This adds support for boards based on the STA2X11 IO-Hub,
          a.k.a. "ConneXt". The chip is used in place of the standard
@@@ -755,9 -755,6 +756,9 @@@ config PARAVIR
          over full virtualization.  However, when run without a hypervisor
          the kernel is theoretically slower and slightly larger.
  
 +config PARAVIRT_XXL
 +      bool
 +
  config PARAVIRT_DEBUG
        bool "paravirt-ops debugging"
        depends on PARAVIRT && DEBUG_KERNEL
@@@ -803,6 -800,7 +804,6 @@@ config KVM_GUES
  config KVM_DEBUG_FS
        bool "Enable debug information for KVM Guests in debugfs"
        depends on KVM_GUEST && DEBUG_FS
 -      default n
        ---help---
          This option enables collection of various statistics for KVM guest.
          Statistics are displayed in debugfs filesystem. Enabling this option
  config PARAVIRT_TIME_ACCOUNTING
        bool "Paravirtual steal time accounting"
        depends on PARAVIRT
 -      default n
        ---help---
          Select this option to enable fine granularity task steal time
          accounting. Time spent executing other tasks in parallel with
@@@ -1170,6 -1169,7 +1171,6 @@@ source "arch/x86/events/Kconfig
  
  config X86_LEGACY_VM86
        bool "Legacy VM86 support"
 -      default n
        depends on X86_32
        ---help---
          This option allows user programs to put the CPU into V8086
@@@ -1492,14 -1492,6 +1493,14 @@@ config X86_DIRECT_GBPAGE
          supports them), so don't confuse the user by printing
          that we have them enabled.
  
 +config X86_CPA_STATISTICS
 +      bool "Enable statistic for Change Page Attribute"
 +      depends on DEBUG_FS
 +      ---help---
 +        Expose statistics about the Change Page Attribute mechanims, which
 +        helps to determine the effectivness of preserving large and huge
 +        page mappings when mapping protections are changed.
 +
  config ARCH_HAS_MEM_ENCRYPT
        def_bool y
  
@@@ -2229,6 -2221,7 +2230,6 @@@ config HOTPLUG_CP
  
  config BOOTPARAM_HOTPLUG_CPU0
        bool "Set default setting of cpu0_hotpluggable"
 -      default n
        depends on HOTPLUG_CPU
        ---help---
          Set whether default state of cpu0_hotpluggable is on or off.
@@@ -2430,7 -2423,7 +2431,7 @@@ menu "Power management and ACPI options
  
  config ARCH_HIBERNATION_HEADER
        def_bool y
 -      depends on X86_64 && HIBERNATION
 +      depends on HIBERNATION
  
  source "kernel/power/Kconfig"
  
@@@ -2750,7 -2743,8 +2751,7 @@@ config OLP
  
  config OLPC_XO1_PM
        bool "OLPC XO-1 Power Management"
 -      depends on OLPC && MFD_CS5535 && PM_SLEEP
 -      select MFD_CORE
 +      depends on OLPC && MFD_CS5535=y && PM_SLEEP
        ---help---
          Add support for poweroff and suspend of the OLPC XO-1 laptop.
  
@@@ -2832,6 -2826,7 +2833,6 @@@ source "drivers/pcmcia/Kconfig
  config RAPIDIO
        tristate "RapidIO support"
        depends on PCI
 -      default n
        help
          If enabled this option will include drivers and the core
          infrastructure code to support RapidIO interconnect devices.
@@@ -37,10 -37,8 +37,10 @@@ struct pt_regs 
        unsigned short __esh;
        unsigned short fs;
        unsigned short __fsh;
 +      /* On interrupt, gs and __gsh store the vector number. */
        unsigned short gs;
        unsigned short __gsh;
 +      /* On interrupt, this is the error code. */
        unsigned long orig_ax;
        unsigned long ip;
        unsigned short cs;
@@@ -146,7 -144,7 +146,7 @@@ static inline int v8086_mode(struct pt_
  static inline bool user_64bit_mode(struct pt_regs *regs)
  {
  #ifdef CONFIG_X86_64
 -#ifndef CONFIG_PARAVIRT
 +#ifndef CONFIG_PARAVIRT_XXL
        /*
         * On non-paravirt systems, this is the only long mode CPL 3
         * selector.  We do not allow long mode selectors in the LDT.
@@@ -238,54 -236,64 +238,92 @@@ static inline int regs_within_kernel_st
                (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
  }
  
 +/**
 + * regs_get_kernel_stack_nth_addr() - get the address of the Nth entry on stack
 + * @regs:     pt_regs which contains kernel stack pointer.
 + * @n:                stack entry number.
 + *
 + * regs_get_kernel_stack_nth() returns the address of the @n th entry of the
 + * kernel stack which is specified by @regs. If the @n th entry is NOT in
 + * the kernel stack, this returns NULL.
 + */
 +static inline unsigned long *regs_get_kernel_stack_nth_addr(struct pt_regs *regs, unsigned int n)
 +{
 +      unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
 +
 +      addr += n;
 +      if (regs_within_kernel_stack(regs, (unsigned long)addr))
 +              return addr;
 +      else
 +              return NULL;
 +}
 +
 +/* To avoid include hell, we can't include uaccess.h */
 +extern long probe_kernel_read(void *dst, const void *src, size_t size);
 +
  /**
   * regs_get_kernel_stack_nth() - get Nth entry of the stack
   * @regs:     pt_regs which contains kernel stack pointer.
   * @n:                stack entry number.
   *
   * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
 - * is specified by @regs. If the @n th entry is NOT in the kernel stack,
 + * is specified by @regs. If the @n th entry is NOT in the kernel stack
   * this returns 0.
   */
  static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
                                                      unsigned int n)
  {
 -      unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
 -      addr += n;
 -      if (regs_within_kernel_stack(regs, (unsigned long)addr))
 -              return *addr;
 -      else
 -              return 0;
 +      unsigned long *addr;
 +      unsigned long val;
 +      long ret;
 +
 +      addr = regs_get_kernel_stack_nth_addr(regs, n);
 +      if (addr) {
 +              ret = probe_kernel_read(&val, addr, sizeof(val));
 +              if (!ret)
 +                      return val;
 +      }
 +      return 0;
  }
  
+ /**
+  * regs_get_kernel_argument() - get Nth function argument in kernel
+  * @regs:     pt_regs of that context
+  * @n:                function argument number (start from 0)
+  *
+  * regs_get_argument() returns @n th argument of the function call.
+  * Note that this chooses most probably assignment, in some case
+  * it can be incorrect.
+  * This is expected to be called from kprobes or ftrace with regs
+  * where the top of stack is the return address.
+  */
+ static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs,
+                                                    unsigned int n)
+ {
+       static const unsigned int argument_offs[] = {
+ #ifdef __i386__
+               offsetof(struct pt_regs, ax),
+               offsetof(struct pt_regs, cx),
+               offsetof(struct pt_regs, dx),
+ #define NR_REG_ARGUMENTS 3
+ #else
+               offsetof(struct pt_regs, di),
+               offsetof(struct pt_regs, si),
+               offsetof(struct pt_regs, dx),
+               offsetof(struct pt_regs, cx),
+               offsetof(struct pt_regs, r8),
+               offsetof(struct pt_regs, r9),
+ #define NR_REG_ARGUMENTS 6
+ #endif
+       };
+       if (n >= NR_REG_ARGUMENTS) {
+               n -= NR_REG_ARGUMENTS - 1;
+               return regs_get_kernel_stack_nth(regs, n);
+       } else
+               return regs_get_register(regs, argument_offs[n]);
+ }
  #define arch_has_single_step()        (1)
  #ifdef CONFIG_X86_DEBUGCTLMSR
  #define arch_has_block_step() (1)
  #define arch_has_block_step() (boot_cpu_data.x86 >= 6)
  #endif
  
 -#define ARCH_HAS_USER_SINGLE_STEP_INFO
 +#define ARCH_HAS_USER_SINGLE_STEP_REPORT
  
  /*
   * When hitting ptrace_stop(), we cannot return using SYSRET because
diff --combined kernel/events/core.c
@@@ -3935,12 -3935,6 +3935,12 @@@ int perf_event_read_local(struct perf_e
                goto out;
        }
  
 +      /* If this is a pinned event it must be running on this CPU */
 +      if (event->attr.pinned && event->oncpu != smp_processor_id()) {
 +              ret = -EBUSY;
 +              goto out;
 +      }
 +
        /*
         * If the event is currently on this CPU, its either a per-task event,
         * or local to this CPU. Furthermore it means its ACTIVE (otherwise
@@@ -8314,8 -8308,6 +8314,8 @@@ void perf_tp_event(u16 event_type, u64 
                        goto unlock;
  
                list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
 +                      if (event->cpu != smp_processor_id())
 +                              continue;
                        if (event->attr.type != PERF_TYPE_TRACEPOINT)
                                continue;
                        if (event->attr.config != entry->type)
@@@ -8376,30 -8368,39 +8376,39 @@@ static struct pmu perf_tracepoint = 
   *
   * PERF_PROBE_CONFIG_IS_RETPROBE if set, create kretprobe/uretprobe
   *                               if not set, create kprobe/uprobe
+  *
+  * The following values specify a reference counter (or semaphore in the
+  * terminology of tools like dtrace, systemtap, etc.) Userspace Statically
+  * Defined Tracepoints (USDT). Currently, we use 40 bit for the offset.
+  *
+  * PERF_UPROBE_REF_CTR_OFFSET_BITS    # of bits in config as th offset
+  * PERF_UPROBE_REF_CTR_OFFSET_SHIFT   # of bits to shift left
   */
  enum perf_probe_config {
        PERF_PROBE_CONFIG_IS_RETPROBE = 1U << 0,  /* [k,u]retprobe */
+       PERF_UPROBE_REF_CTR_OFFSET_BITS = 32,
+       PERF_UPROBE_REF_CTR_OFFSET_SHIFT = 64 - PERF_UPROBE_REF_CTR_OFFSET_BITS,
  };
  
  PMU_FORMAT_ATTR(retprobe, "config:0");
+ #endif
  
- static struct attribute *probe_attrs[] = {
+ #ifdef CONFIG_KPROBE_EVENTS
+ static struct attribute *kprobe_attrs[] = {
        &format_attr_retprobe.attr,
        NULL,
  };
  
- static struct attribute_group probe_format_group = {
+ static struct attribute_group kprobe_format_group = {
        .name = "format",
-       .attrs = probe_attrs,
+       .attrs = kprobe_attrs,
  };
  
- static const struct attribute_group *probe_attr_groups[] = {
-       &probe_format_group,
+ static const struct attribute_group *kprobe_attr_groups[] = {
+       &kprobe_format_group,
        NULL,
  };
- #endif
  
- #ifdef CONFIG_KPROBE_EVENTS
  static int perf_kprobe_event_init(struct perf_event *event);
  static struct pmu perf_kprobe = {
        .task_ctx_nr    = perf_sw_context,
        .start          = perf_swevent_start,
        .stop           = perf_swevent_stop,
        .read           = perf_swevent_read,
-       .attr_groups    = probe_attr_groups,
+       .attr_groups    = kprobe_attr_groups,
  };
  
  static int perf_kprobe_event_init(struct perf_event *event)
  #endif /* CONFIG_KPROBE_EVENTS */
  
  #ifdef CONFIG_UPROBE_EVENTS
+ PMU_FORMAT_ATTR(ref_ctr_offset, "config:32-63");
+ static struct attribute *uprobe_attrs[] = {
+       &format_attr_retprobe.attr,
+       &format_attr_ref_ctr_offset.attr,
+       NULL,
+ };
+ static struct attribute_group uprobe_format_group = {
+       .name = "format",
+       .attrs = uprobe_attrs,
+ };
+ static const struct attribute_group *uprobe_attr_groups[] = {
+       &uprobe_format_group,
+       NULL,
+ };
  static int perf_uprobe_event_init(struct perf_event *event);
  static struct pmu perf_uprobe = {
        .task_ctx_nr    = perf_sw_context,
        .start          = perf_swevent_start,
        .stop           = perf_swevent_stop,
        .read           = perf_swevent_read,
-       .attr_groups    = probe_attr_groups,
+       .attr_groups    = uprobe_attr_groups,
  };
  
  static int perf_uprobe_event_init(struct perf_event *event)
  {
        int err;
+       unsigned long ref_ctr_offset;
        bool is_retprobe;
  
        if (event->attr.type != perf_uprobe.type)
                return -EOPNOTSUPP;
  
        is_retprobe = event->attr.config & PERF_PROBE_CONFIG_IS_RETPROBE;
-       err = perf_uprobe_init(event, is_retprobe);
+       ref_ctr_offset = event->attr.config >> PERF_UPROBE_REF_CTR_OFFSET_SHIFT;
+       err = perf_uprobe_init(event, ref_ctr_offset, is_retprobe);
        if (err)
                return err;
  
@@@ -9433,7 -9454,9 +9462,7 @@@ static void free_pmu_context(struct pm
        if (pmu->task_ctx_nr > perf_invalid_context)
                return;
  
 -      mutex_lock(&pmus_lock);
        free_percpu(pmu->pmu_cpu_context);
 -      mutex_unlock(&pmus_lock);
  }
  
  /*
@@@ -9689,8 -9712,12 +9718,8 @@@ EXPORT_SYMBOL_GPL(perf_pmu_register)
  
  void perf_pmu_unregister(struct pmu *pmu)
  {
 -      int remove_device;
 -
        mutex_lock(&pmus_lock);
 -      remove_device = pmu_bus_running;
        list_del_rcu(&pmu->entry);
 -      mutex_unlock(&pmus_lock);
  
        /*
         * We dereference the pmu list under both SRCU and regular RCU, so
        free_percpu(pmu->pmu_disable_count);
        if (pmu->type >= PERF_TYPE_MAX)
                idr_remove(&pmu_idr, pmu->type);
 -      if (remove_device) {
 +      if (pmu_bus_running) {
                if (pmu->nr_addr_filters)
                        device_remove_file(pmu->dev, &dev_attr_nr_addr_filters);
                device_del(pmu->dev);
                put_device(pmu->dev);
        }
        free_pmu_context(pmu);
 +      mutex_unlock(&pmus_lock);
  }
  EXPORT_SYMBOL_GPL(perf_pmu_unregister);
  
diff --combined kernel/events/uprobes.c
@@@ -73,6 -73,7 +73,7 @@@ struct uprobe 
        struct uprobe_consumer  *consumers;
        struct inode            *inode;         /* Also hold a ref to inode */
        loff_t                  offset;
+       loff_t                  ref_ctr_offset;
        unsigned long           flags;
  
        /*
        struct arch_uprobe      arch;
  };
  
+ struct delayed_uprobe {
+       struct list_head list;
+       struct uprobe *uprobe;
+       struct mm_struct *mm;
+ };
+ static DEFINE_MUTEX(delayed_uprobe_lock);
+ static LIST_HEAD(delayed_uprobe_list);
  /*
   * Execute out of line area: anonymous executable mapping installed
   * by the probed task to execute the copy of the original instruction
@@@ -282,6 -292,166 +292,166 @@@ static int verify_opcode(struct page *p
        return 1;
  }
  
+ static struct delayed_uprobe *
+ delayed_uprobe_check(struct uprobe *uprobe, struct mm_struct *mm)
+ {
+       struct delayed_uprobe *du;
+       list_for_each_entry(du, &delayed_uprobe_list, list)
+               if (du->uprobe == uprobe && du->mm == mm)
+                       return du;
+       return NULL;
+ }
+ static int delayed_uprobe_add(struct uprobe *uprobe, struct mm_struct *mm)
+ {
+       struct delayed_uprobe *du;
+       if (delayed_uprobe_check(uprobe, mm))
+               return 0;
+       du  = kzalloc(sizeof(*du), GFP_KERNEL);
+       if (!du)
+               return -ENOMEM;
+       du->uprobe = uprobe;
+       du->mm = mm;
+       list_add(&du->list, &delayed_uprobe_list);
+       return 0;
+ }
+ static void delayed_uprobe_delete(struct delayed_uprobe *du)
+ {
+       if (WARN_ON(!du))
+               return;
+       list_del(&du->list);
+       kfree(du);
+ }
+ static void delayed_uprobe_remove(struct uprobe *uprobe, struct mm_struct *mm)
+ {
+       struct list_head *pos, *q;
+       struct delayed_uprobe *du;
+       if (!uprobe && !mm)
+               return;
+       list_for_each_safe(pos, q, &delayed_uprobe_list) {
+               du = list_entry(pos, struct delayed_uprobe, list);
+               if (uprobe && du->uprobe != uprobe)
+                       continue;
+               if (mm && du->mm != mm)
+                       continue;
+               delayed_uprobe_delete(du);
+       }
+ }
+ static bool valid_ref_ctr_vma(struct uprobe *uprobe,
+                             struct vm_area_struct *vma)
+ {
+       unsigned long vaddr = offset_to_vaddr(vma, uprobe->ref_ctr_offset);
+       return uprobe->ref_ctr_offset &&
+               vma->vm_file &&
+               file_inode(vma->vm_file) == uprobe->inode &&
+               (vma->vm_flags & (VM_WRITE|VM_SHARED)) == VM_WRITE &&
+               vma->vm_start <= vaddr &&
+               vma->vm_end > vaddr;
+ }
+ static struct vm_area_struct *
+ find_ref_ctr_vma(struct uprobe *uprobe, struct mm_struct *mm)
+ {
+       struct vm_area_struct *tmp;
+       for (tmp = mm->mmap; tmp; tmp = tmp->vm_next)
+               if (valid_ref_ctr_vma(uprobe, tmp))
+                       return tmp;
+       return NULL;
+ }
+ static int
+ __update_ref_ctr(struct mm_struct *mm, unsigned long vaddr, short d)
+ {
+       void *kaddr;
+       struct page *page;
+       struct vm_area_struct *vma;
+       int ret;
+       short *ptr;
+       if (!vaddr || !d)
+               return -EINVAL;
+       ret = get_user_pages_remote(NULL, mm, vaddr, 1,
+                       FOLL_WRITE, &page, &vma, NULL);
+       if (unlikely(ret <= 0)) {
+               /*
+                * We are asking for 1 page. If get_user_pages_remote() fails,
+                * it may return 0, in that case we have to return error.
+                */
+               return ret == 0 ? -EBUSY : ret;
+       }
+       kaddr = kmap_atomic(page);
+       ptr = kaddr + (vaddr & ~PAGE_MASK);
+       if (unlikely(*ptr + d < 0)) {
+               pr_warn("ref_ctr going negative. vaddr: 0x%lx, "
+                       "curr val: %d, delta: %d\n", vaddr, *ptr, d);
+               ret = -EINVAL;
+               goto out;
+       }
+       *ptr += d;
+       ret = 0;
+ out:
+       kunmap_atomic(kaddr);
+       put_page(page);
+       return ret;
+ }
+ static void update_ref_ctr_warn(struct uprobe *uprobe,
+                               struct mm_struct *mm, short d)
+ {
+       pr_warn("ref_ctr %s failed for inode: 0x%lx offset: "
+               "0x%llx ref_ctr_offset: 0x%llx of mm: 0x%pK\n",
+               d > 0 ? "increment" : "decrement", uprobe->inode->i_ino,
+               (unsigned long long) uprobe->offset,
+               (unsigned long long) uprobe->ref_ctr_offset, mm);
+ }
+ static int update_ref_ctr(struct uprobe *uprobe, struct mm_struct *mm,
+                         short d)
+ {
+       struct vm_area_struct *rc_vma;
+       unsigned long rc_vaddr;
+       int ret = 0;
+       rc_vma = find_ref_ctr_vma(uprobe, mm);
+       if (rc_vma) {
+               rc_vaddr = offset_to_vaddr(rc_vma, uprobe->ref_ctr_offset);
+               ret = __update_ref_ctr(mm, rc_vaddr, d);
+               if (ret)
+                       update_ref_ctr_warn(uprobe, mm, d);
+               if (d > 0)
+                       return ret;
+       }
+       mutex_lock(&delayed_uprobe_lock);
+       if (d > 0)
+               ret = delayed_uprobe_add(uprobe, mm);
+       else
+               delayed_uprobe_remove(uprobe, mm);
+       mutex_unlock(&delayed_uprobe_lock);
+       return ret;
+ }
  /*
   * NOTE:
   * Expect the breakpoint instruction to be the smallest size instruction for
  int uprobe_write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm,
                        unsigned long vaddr, uprobe_opcode_t opcode)
  {
+       struct uprobe *uprobe;
        struct page *old_page, *new_page;
        struct vm_area_struct *vma;
-       int ret;
+       int ret, is_register, ref_ctr_updated = 0;
+       is_register = is_swbp_insn(&opcode);
+       uprobe = container_of(auprobe, struct uprobe, arch);
  
  retry:
        /* Read the page with vaddr into memory */
        if (ret <= 0)
                goto put_old;
  
+       /* We are going to replace instruction, update ref_ctr. */
+       if (!ref_ctr_updated && uprobe->ref_ctr_offset) {
+               ret = update_ref_ctr(uprobe, mm, is_register ? 1 : -1);
+               if (ret)
+                       goto put_old;
+               ref_ctr_updated = 1;
+       }
        ret = anon_vma_prepare(vma);
        if (ret)
                goto put_old;
@@@ -337,6 -520,11 +520,11 @@@ put_old
  
        if (unlikely(ret == -EAGAIN))
                goto retry;
+       /* Revert back reference counter if instruction update failed. */
+       if (ret && is_register && ref_ctr_updated)
+               update_ref_ctr(uprobe, mm, -1);
        return ret;
  }
  
@@@ -378,8 -566,15 +566,15 @@@ static struct uprobe *get_uprobe(struc
  
  static void put_uprobe(struct uprobe *uprobe)
  {
-       if (atomic_dec_and_test(&uprobe->ref))
+       if (atomic_dec_and_test(&uprobe->ref)) {
+               /*
+                * If application munmap(exec_vma) before uprobe_unregister()
+                * gets called, we don't get a chance to remove uprobe from
+                * delayed_uprobe_list from remove_breakpoint(). Do it here.
+                */
+               delayed_uprobe_remove(uprobe, NULL);
                kfree(uprobe);
+       }
  }
  
  static int match_uprobe(struct uprobe *l, struct uprobe *r)
@@@ -484,7 -679,18 +679,18 @@@ static struct uprobe *insert_uprobe(str
        return u;
  }
  
- static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset)
+ static void
+ ref_ctr_mismatch_warn(struct uprobe *cur_uprobe, struct uprobe *uprobe)
+ {
+       pr_warn("ref_ctr_offset mismatch. inode: 0x%lx offset: 0x%llx "
+               "ref_ctr_offset(old): 0x%llx ref_ctr_offset(new): 0x%llx\n",
+               uprobe->inode->i_ino, (unsigned long long) uprobe->offset,
+               (unsigned long long) cur_uprobe->ref_ctr_offset,
+               (unsigned long long) uprobe->ref_ctr_offset);
+ }
+ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset,
+                                  loff_t ref_ctr_offset)
  {
        struct uprobe *uprobe, *cur_uprobe;
  
  
        uprobe->inode = inode;
        uprobe->offset = offset;
+       uprobe->ref_ctr_offset = ref_ctr_offset;
        init_rwsem(&uprobe->register_rwsem);
        init_rwsem(&uprobe->consumer_rwsem);
  
        cur_uprobe = insert_uprobe(uprobe);
        /* a uprobe exists for this inode:offset combination */
        if (cur_uprobe) {
+               if (cur_uprobe->ref_ctr_offset != uprobe->ref_ctr_offset) {
+                       ref_ctr_mismatch_warn(cur_uprobe, uprobe);
+                       put_uprobe(cur_uprobe);
+                       kfree(uprobe);
+                       return ERR_PTR(-EINVAL);
+               }
                kfree(uprobe);
                uprobe = cur_uprobe;
        }
@@@ -895,7 -1108,7 +1108,7 @@@ EXPORT_SYMBOL_GPL(uprobe_unregister)
   * else return 0 (success)
   */
  static int __uprobe_register(struct inode *inode, loff_t offset,
-                            struct uprobe_consumer *uc)
+                            loff_t ref_ctr_offset, struct uprobe_consumer *uc)
  {
        struct uprobe *uprobe;
        int ret;
                return -EINVAL;
  
   retry:
-       uprobe = alloc_uprobe(inode, offset);
+       uprobe = alloc_uprobe(inode, offset, ref_ctr_offset);
        if (!uprobe)
                return -ENOMEM;
+       if (IS_ERR(uprobe))
+               return PTR_ERR(uprobe);
        /*
         * We can race with uprobe_unregister()->delete_uprobe().
         * Check uprobe_is_active() and retry if it is false.
  int uprobe_register(struct inode *inode, loff_t offset,
                    struct uprobe_consumer *uc)
  {
-       return __uprobe_register(inode, offset, uc);
+       return __uprobe_register(inode, offset, 0, uc);
  }
  EXPORT_SYMBOL_GPL(uprobe_register);
  
+ int uprobe_register_refctr(struct inode *inode, loff_t offset,
+                          loff_t ref_ctr_offset, struct uprobe_consumer *uc)
+ {
+       return __uprobe_register(inode, offset, ref_ctr_offset, uc);
+ }
+ EXPORT_SYMBOL_GPL(uprobe_register_refctr);
  /*
   * uprobe_apply - unregister an already registered probe.
   * @inode: the file in which the probe has to be removed.
@@@ -1060,6 -1283,35 +1283,35 @@@ static void build_probe_list(struct ino
        spin_unlock(&uprobes_treelock);
  }
  
+ /* @vma contains reference counter, not the probed instruction. */
+ static int delayed_ref_ctr_inc(struct vm_area_struct *vma)
+ {
+       struct list_head *pos, *q;
+       struct delayed_uprobe *du;
+       unsigned long vaddr;
+       int ret = 0, err = 0;
+       mutex_lock(&delayed_uprobe_lock);
+       list_for_each_safe(pos, q, &delayed_uprobe_list) {
+               du = list_entry(pos, struct delayed_uprobe, list);
+               if (du->mm != vma->vm_mm ||
+                   !valid_ref_ctr_vma(du->uprobe, vma))
+                       continue;
+               vaddr = offset_to_vaddr(vma, du->uprobe->ref_ctr_offset);
+               ret = __update_ref_ctr(vma->vm_mm, vaddr, 1);
+               if (ret) {
+                       update_ref_ctr_warn(du->uprobe, vma->vm_mm, 1);
+                       if (!err)
+                               err = ret;
+               }
+               delayed_uprobe_delete(du);
+       }
+       mutex_unlock(&delayed_uprobe_lock);
+       return err;
+ }
  /*
   * Called from mmap_region/vma_adjust with mm->mmap_sem acquired.
   *
@@@ -1072,7 -1324,15 +1324,15 @@@ int uprobe_mmap(struct vm_area_struct *
        struct uprobe *uprobe, *u;
        struct inode *inode;
  
-       if (no_uprobe_events() || !valid_vma(vma, true))
+       if (no_uprobe_events())
+               return 0;
+       if (vma->vm_file &&
+           (vma->vm_flags & (VM_WRITE|VM_SHARED)) == VM_WRITE &&
+           test_bit(MMF_HAS_UPROBES, &vma->vm_mm->flags))
+               delayed_ref_ctr_inc(vma);
+       if (!valid_vma(vma, true))
                return 0;
  
        inode = file_inode(vma->vm_file);
@@@ -1246,6 -1506,10 +1506,10 @@@ void uprobe_clear_state(struct mm_struc
  {
        struct xol_area *area = mm->uprobes_state.xol_area;
  
+       mutex_lock(&delayed_uprobe_lock);
+       delayed_uprobe_remove(NULL, mm);
+       mutex_unlock(&delayed_uprobe_lock);
        if (!area)
                return;
  
@@@ -1858,7 -2122,7 +2122,7 @@@ static void handle_trampoline(struct pt
  
   sigill:
        uprobe_warn(current, "handle uretprobe, sending SIGILL.");
 -      force_sig_info(SIGILL, SEND_SIG_FORCED, current);
 +      force_sig(SIGILL, current);
  
  }
  
@@@ -1966,7 -2230,7 +2230,7 @@@ static void handle_singlestep(struct up
  
        if (unlikely(err)) {
                uprobe_warn(current, "execute the probed insn, sending SIGILL.");
 -              force_sig_info(SIGILL, SEND_SIG_FORCED, current);
 +              force_sig(SIGILL, current);
        }
  }