diff options
author | H. Nikolaus Schaller <hns@goldelico.com> | 2013-11-04 10:10:39 +0100 |
---|---|---|
committer | H. Nikolaus Schaller <hns@goldelico.com> | 2013-11-04 10:48:16 +0100 |
commit | a01de07a85d70c1a15a0d1b078f4c649ec49c958 (patch) | |
tree | bef64102693547e05ae23b3f99f3488f787d302e /kernel | |
parent | 8c52a7cf8e066d7ce202e38863c225a7d4d0bfeb (diff) | |
parent | 5e01dc7b26d9f24f39abace5da98ccbd6a5ceb52 (diff) | |
download | kernel_goldelico_gta04-a01de07a85d70c1a15a0d1b078f4c649ec49c958.zip kernel_goldelico_gta04-a01de07a85d70c1a15a0d1b078f4c649ec49c958.tar.gz kernel_goldelico_gta04-a01de07a85d70c1a15a0d1b078f4c649ec49c958.tar.bz2 |
This is now Linux-3.12.0 for the GTA04!
Merge remote-tracking branch 'linus/master'
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/events/ring_buffer.c | 31 |
1 files changed, 27 insertions, 4 deletions
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c index cd55144..9c2ddfb 100644 --- a/kernel/events/ring_buffer.c +++ b/kernel/events/ring_buffer.c @@ -87,10 +87,31 @@ again: goto out; /* - * Publish the known good head. Rely on the full barrier implied - * by atomic_dec_and_test() order the rb->head read and this - * write. + * Since the mmap() consumer (userspace) can run on a different CPU: + * + * kernel user + * + * READ ->data_tail READ ->data_head + * smp_mb() (A) smp_rmb() (C) + * WRITE $data READ $data + * smp_wmb() (B) smp_mb() (D) + * STORE ->data_head WRITE ->data_tail + * + * Where A pairs with D, and B pairs with C. + * + * I don't think A needs to be a full barrier because we won't in fact + * write data until we see the store from userspace. So we simply don't + * issue the data WRITE until we observe it. Be conservative for now. + * + * OTOH, D needs to be a full barrier since it separates the data READ + * from the tail WRITE. + * + * For B a WMB is sufficient since it separates two WRITEs, and for C + * an RMB is sufficient since it separates two READs. + * + * See perf_output_begin(). */ + smp_wmb(); rb->user_page->data_head = head; /* @@ -154,9 +175,11 @@ int perf_output_begin(struct perf_output_handle *handle, * Userspace could choose to issue a mb() before updating the * tail pointer. So that all reads will be completed before the * write is issued. + * + * See perf_output_put_handle(). */ tail = ACCESS_ONCE(rb->user_page->data_tail); - smp_rmb(); + smp_mb(); offset = head = local_read(&rb->head); head += size; if (unlikely(!perf_output_space(rb, tail, offset, head))) |