diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c index 8e8584a2d4c3..0ea14666e970 100644 --- a/arch/arm64/kvm/hyp_trace.c +++ b/arch/arm64/kvm/hyp_trace.c @@ -641,6 +641,85 @@ static const struct file_operations hyp_trace_pipe_fops = { .llseek = no_llseek, }; +static ssize_t +hyp_trace_raw_read(struct file *file, char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + struct ht_iterator *iter = (struct ht_iterator *)file->private_data; + struct trace_buffer *trace_buffer = iter->trace_buffer; + size_t size; + int ret; + + if (iter->copy_leftover) + goto read; +again: + hyp_trace_read_start(iter->cpu); + ret = ring_buffer_read_page(trace_buffer, &iter->spare, + cnt, iter->cpu, 0); + hyp_trace_read_stop(iter->cpu); + if (ret < 0) { + if (!ring_buffer_empty_cpu(iter->trace_buffer, iter->cpu)) + return 0; + + ret = ring_buffer_wait(trace_buffer, iter->cpu, 0); + if (ret < 0) + return ret; + + goto again; + } + + iter->copy_leftover = 0; +read: + size = PAGE_SIZE - iter->copy_leftover; + if (size > cnt) + size = cnt; + + ret = copy_to_user(ubuf, iter->spare + PAGE_SIZE - size, size); + if (ret == size) + return -EFAULT; + + size -= ret; + *ppos += size; + iter->copy_leftover = ret; + + return size; +} + +static int hyp_trace_raw_open(struct inode *inode, struct file *file) +{ + int ret = hyp_trace_pipe_open(inode, file); + struct ht_iterator *iter; + + if (ret) + return ret; + + iter = file->private_data; + iter->spare = ring_buffer_alloc_read_page(iter->trace_buffer, iter->cpu); + if (IS_ERR(iter->spare)) { + ret = PTR_ERR(iter->spare); + iter->spare = NULL; + return ret; + } + + return 0; +} + +static int hyp_trace_raw_release(struct inode *inode, struct file *file) +{ + struct ht_iterator *iter = file->private_data; + + ring_buffer_free_read_page(iter->trace_buffer, iter->cpu, iter->spare); + + return hyp_trace_pipe_release(inode, file); +} + +static const struct file_operations hyp_trace_raw_fops = { + .open = hyp_trace_raw_open, + .read = hyp_trace_raw_read, + .release = hyp_trace_raw_release, + .llseek = no_llseek, +}; + static void hyp_tracefs_create_cpu_file(const char *file_name, unsigned long cpu, const struct file_operations *fops, @@ -700,6 +779,8 @@ int init_hyp_tracefs(void) hyp_tracefs_create_cpu_file("trace", cpu, &hyp_trace_fops, dir); hyp_tracefs_create_cpu_file("trace_pipe", cpu, &hyp_trace_pipe_fops, dir); + hyp_tracefs_create_cpu_file("trace_pipe_raw", cpu, + &hyp_trace_raw_fops, dir); } kvm_hyp_init_events_tracefs(root_dir); diff --git a/arch/arm64/kvm/hyp_trace.h b/arch/arm64/kvm/hyp_trace.h index 7d062ec9bf19..fb8172e464f2 100644 --- a/arch/arm64/kvm/hyp_trace.h +++ b/arch/arm64/kvm/hyp_trace.h @@ -12,6 +12,8 @@ struct ht_iterator { struct hyp_entry_hdr *ent; struct trace_seq seq; u64 ts; + void *spare; + size_t copy_leftover; size_t ent_size; struct delayed_work poke_work; unsigned long lost_events; diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 7d1bccc16e94..4d5ce7f6c578 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -5729,9 +5729,6 @@ void *ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu) unsigned long flags; struct page *page; - if (unlikely(has_ext_writer(buffer))) - return ERR_PTR(-EINVAL); - if (!cpumask_test_cpu(cpu, buffer->cpumask)) return ERR_PTR(-ENODEV); @@ -5846,9 +5843,6 @@ int ring_buffer_read_page(struct trace_buffer *buffer, u64 save_timestamp; int ret = -1; - if (unlikely(has_ext_writer(buffer))) - goto out; - if (!cpumask_test_cpu(cpu, buffer->cpumask)) goto out; @@ -5955,14 +5949,21 @@ int ring_buffer_read_page(struct trace_buffer *buffer, cpu_buffer->read += rb_page_entries(reader); cpu_buffer->read_bytes += BUF_PAGE_SIZE; - /* swap the pages */ - rb_init_page(bpage); - bpage = reader->page; - reader->page = *data_page; - local_set(&reader->write, 0); - local_set(&reader->entries, 0); - reader->read = 0; - *data_page = bpage; + if (unlikely(has_ext_writer(buffer))) { + u64 commit = local_read(&reader->page->commit); + + memcpy(bpage, reader->page, + BUF_PAGE_HDR_SIZE + commit); + } else { + /* swap the pages */ + rb_init_page(bpage); + bpage = reader->page; + reader->page = *data_page; + local_set(&reader->write, 0); + local_set(&reader->entries, 0); + reader->read = 0; + *data_page = bpage; + } /* * Use the real_end for the data size,