static bool combine_locks;
 static bool show_thread_stats;
 static bool show_lock_addrs;
+static bool show_lock_owner;
 static bool use_bpf;
 static unsigned long bpf_map_entries = 10240;
 static int max_stack_depth = CONTENTION_STACK_DEPTH;
 
                switch (aggr_mode) {
                case LOCK_AGGR_TASK:
-                       pr_info("  %10s   %s\n\n", "pid", "comm");
+                       pr_info("  %10s   %s\n\n", "pid",
+                               show_lock_owner ? "owner" : "comm");
                        break;
                case LOCK_AGGR_CALLER:
                        pr_info("  %10s   %s\n\n", "type", "caller");
                case LOCK_AGGR_TASK:
                        pid = st->addr;
                        t = perf_session__findnew(session, pid);
-                       pr_info("  %10d   %s\n", pid, thread__comm_str(t));
+                       pr_info("  %10d   %s\n",
+                               pid, pid == -1 ? "Unknown" : thread__comm_str(t));
                        break;
                case LOCK_AGGR_ADDR:
                        pr_info("  %016llx   %s\n", (unsigned long long)st->addr,
 {
 }
 
+static int check_lock_contention_options(const struct option *options,
+                                        const char * const *usage)
+
+{
+       if (show_thread_stats && show_lock_addrs) {
+               pr_err("Cannot use thread and addr mode together\n");
+               parse_options_usage(usage, options, "threads", 0);
+               parse_options_usage(NULL, options, "lock-addr", 0);
+               return -1;
+       }
+
+       if (show_lock_owner && !use_bpf) {
+               pr_err("Lock owners are available only with BPF\n");
+               parse_options_usage(usage, options, "lock-owner", 0);
+               parse_options_usage(NULL, options, "use-bpf", 0);
+               return -1;
+       }
+
+       if (show_lock_owner && show_lock_addrs) {
+               pr_err("Cannot use owner and addr mode together\n");
+               parse_options_usage(usage, options, "lock-owner", 0);
+               parse_options_usage(NULL, options, "lock-addr", 0);
+               return -1;
+       }
+
+       if (show_lock_owner)
+               show_thread_stats = true;
+
+       return 0;
+}
+
 static int __cmd_contention(int argc, const char **argv)
 {
        int err = -EINVAL;
                .stack_skip = stack_skip,
                .filters = &filters,
                .save_callstack = needs_callstack(),
+               .owner = show_lock_owner,
        };
 
        session = perf_session__new(use_bpf ? NULL : &data, &eops);
                     "Filter specific address/symbol of locks", parse_lock_addr),
        OPT_CALLBACK('S', "callstack-filter", NULL, "NAMES",
                     "Filter specific function in the callstack", parse_call_stack),
+       OPT_BOOLEAN('o', "lock-owner", &show_lock_owner, "show lock owners instead of waiters"),
        OPT_PARENT(lock_options)
        };
 
                                             contention_usage, 0);
                }
 
-               if (show_thread_stats && show_lock_addrs) {
-                       pr_err("Cannot use thread and addr mode together\n");
-                       parse_options_usage(contention_usage, contention_options,
-                                           "threads", 0);
-                       parse_options_usage(NULL, contention_options,
-                                           "lock-addr", 0);
+               if (check_lock_contention_options(contention_options,
+                                                 contention_usage) < 0)
                        return -1;
-               }
 
                rc = __cmd_contention(argc, argv);
        } else {
 
 /* default buffer size */
 #define MAX_ENTRIES  10240
 
+/* lock contention flags from include/trace/events/lock.h */
+#define LCB_F_SPIN     (1U << 0)
+#define LCB_F_READ     (1U << 1)
+#define LCB_F_WRITE    (1U << 2)
+#define LCB_F_RT       (1U << 3)
+#define LCB_F_PERCPU   (1U << 4)
+#define LCB_F_MUTEX    (1U << 5)
+
 struct tstamp_data {
        __u64 timestamp;
        __u64 lock;
 int has_addr;
 int needs_callstack;
 int stack_skip;
+int lock_owner;
 
 /* determine the key of lock stat */
 int aggr_mode;
        return 1;
 }
 
-static inline void update_task_data(__u32 pid)
+static inline int update_task_data(struct task_struct *task)
 {
        struct contention_task_data *p;
+       int pid, err;
+
+       err = bpf_core_read(&pid, sizeof(pid), &task->pid);
+       if (err)
+               return -1;
 
        p = bpf_map_lookup_elem(&task_data, &pid);
        if (p == NULL) {
-               struct contention_task_data data;
+               struct contention_task_data data = {};
 
-               bpf_get_current_comm(data.comm, sizeof(data.comm));
+               BPF_CORE_READ_STR_INTO(&data.comm, task, comm);
                bpf_map_update_elem(&task_data, &pid, &data, BPF_NOEXIST);
        }
+
+       return 0;
 }
 
 SEC("tp_btf/contention_begin")
                                                  BPF_F_FAST_STACK_CMP | stack_skip);
                if (pelem->stack_id < 0)
                        lost++;
+       } else if (aggr_mode == LOCK_AGGR_TASK) {
+               struct task_struct *task;
+
+               if (lock_owner) {
+                       if (pelem->flags & LCB_F_MUTEX) {
+                               struct mutex *lock = (void *)pelem->lock;
+                               unsigned long owner = BPF_CORE_READ(lock, owner.counter);
+
+                               task = (void *)(owner & ~7UL);
+                       } else if (pelem->flags == LCB_F_READ || pelem->flags == LCB_F_WRITE) {
+                               struct rw_semaphore *lock = (void *)pelem->lock;
+                               unsigned long owner = BPF_CORE_READ(lock, owner.counter);
+
+                               task = (void *)(owner & ~7UL);
+                       } else {
+                               task = NULL;
+                       }
+
+                       /* The flags is not used anymore.  Pass the owner pid. */
+                       if (task)
+                               pelem->flags = BPF_CORE_READ(task, pid);
+                       else
+                               pelem->flags = -1U;
+
+               } else {
+                       task = bpf_get_current_task_btf();
+               }
+
+               if (task) {
+                       if (update_task_data(task) < 0 && lock_owner)
+                               pelem->flags = -1U;
+               }
        }
 
        return 0;
                key.stack_id = pelem->stack_id;
                break;
        case LOCK_AGGR_TASK:
-               key.pid = pid;
-               update_task_data(pid);
+               if (lock_owner)
+                       key.pid = pelem->flags;
+               else
+                       key.pid = pid;
                if (needs_callstack)
                        key.stack_id = pelem->stack_id;
                break;