The WARN_ON in the ring buffer when a commit is preempted and the buffer is filled by preceding writes can happen in normal operations. The WARN_ON makes it look like a bug, not to mention, because it does not stop tracing and calls printk which can also recurse, this is prone to deadlock (the WARN_ON is not in a position to recurse). This patch removes the WARN_ON and replaces it with a counter that can be retrieved by a tracer. This counter is called commit_overrun. While at it, I added a nmi_dropped counter to count any time an NMI entry is dropped because the NMI could not take the spinlock. [ Impact: prevent deadlock by printing normal case warning ]
Unified · Split
| @@ -153,6 +153,8 @@ unsigned long ring_buffer_entries(struct ring_buffer *buffer); · 152 unmodified lines | ||
| 153 | 153 | unsigned long ring_buffer_overruns(struct ring_buffer *buffer); |
| 154 | 154 | unsigned long ring_buffer_entries_cpu(struct ring_buffer *buffer, int cpu); |
| 155 | 155 | unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu); |
| 156 | +unsigned long ring_buffer_commit_overrun_cpu(struct ring_buffer *buffer, int cpu); | |
| 157 | +unsigned long ring_buffer_nmi_dropped_cpu(struct ring_buffer *buffer, int cpu); | |
| 156 | 158 | |
| 157 | 159 | u64 ring_buffer_time_stamp(struct ring_buffer *buffer, int cpu); |
| 158 | 160 | void ring_buffer_normalize_time_stamp(struct ring_buffer *buffer, |
| @@ -402,6 +402,8 @@ struct ring_buffer_per_cpu { · 401 unmodified lines | ||
| 402 | 402 | struct buffer_page *tail_page; /* write to tail */ |
| 403 | 403 | struct buffer_page *commit_page; /* committed pages */ |
| 404 | 404 | struct buffer_page *reader_page; |
| 405 | + unsigned long nmi_dropped; | |
| 406 | + unsigned long commit_overrun; | |
| 405 | 407 | unsigned long overrun; |
| 406 | 408 | unsigned long entries; |
| 407 | 409 | u64 write_stamp; |
| @@ -1216,8 +1218,10 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, · 808 unmodified lines | ||
| 1216 | 1218 | * simply fail. |
| 1217 | 1219 | */ |
| 1218 | 1220 | if (unlikely(in_nmi())) { |
| 1219 | − if (!__raw_spin_trylock(&cpu_buffer->lock)) | |
| 1221 | + if (!__raw_spin_trylock(&cpu_buffer->lock)) { | |
| 1222 | + cpu_buffer->nmi_dropped++; | |
| 1220 | 1223 | goto out_reset; |
| 1224 | + } | |
| 1221 | 1225 | } else |
| 1222 | 1226 | __raw_spin_lock(&cpu_buffer->lock); |
| 1223 | 1227 | |
| @@ -1238,8 +1242,7 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, · 14 unmodified lines | ||
| 1238 | 1242 | * about it. |
| 1239 | 1243 | */ |
| 1240 | 1244 | if (unlikely(next_page == commit_page)) { |
| 1241 | − /* This can easily happen on small ring buffers */ | |
| 1242 | − WARN_ON_ONCE(buffer->pages > 2); | |
| 1245 | + cpu_buffer->commit_overrun++; | |
| 1243 | 1246 | goto out_reset; |
| 1244 | 1247 | } |
| 1245 | 1248 | |
| @@ -1925,6 +1928,47 @@ unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu) · 679 unmodified lines | ||
| 1925 | 1928 | } |
| 1926 | 1929 | EXPORT_SYMBOL_GPL(ring_buffer_overrun_cpu); |
| 1927 | 1930 | |
| 1931 | +/** | |
| 1932 | + * ring_buffer_nmi_dropped_cpu - get the number of nmis that were dropped | |
| 1933 | + * @buffer: The ring buffer | |
| 1934 | + * @cpu: The per CPU buffer to get the number of overruns from | |
| 1935 | + */ | |
| 1936 | +unsigned long ring_buffer_nmi_dropped_cpu(struct ring_buffer *buffer, int cpu) | |
| 1937 | +{ | |
| 1938 | + struct ring_buffer_per_cpu *cpu_buffer; | |
| 1939 | + unsigned long ret; | |
| 1940 | + | |
| 1941 | + if (!cpumask_test_cpu(cpu, buffer->cpumask)) | |
| 1942 | + return 0; | |
| 1943 | + | |
| 1944 | + cpu_buffer = buffer->buffers[cpu]; | |
| 1945 | + ret = cpu_buffer->nmi_dropped; | |
| 1946 | + | |
| 1947 | + return ret; | |
| 1948 | +} | |
| 1949 | +EXPORT_SYMBOL_GPL(ring_buffer_nmi_dropped_cpu); | |
| 1950 | + | |
| 1951 | +/** | |
| 1952 | + * ring_buffer_commit_overrun_cpu - get the number of overruns caused by commits | |
| 1953 | + * @buffer: The ring buffer | |
| 1954 | + * @cpu: The per CPU buffer to get the number of overruns from | |
| 1955 | + */ | |
| 1956 | +unsigned long | |
| 1957 | +ring_buffer_commit_overrun_cpu(struct ring_buffer *buffer, int cpu) | |
| 1958 | +{ | |
| 1959 | + struct ring_buffer_per_cpu *cpu_buffer; | |
| 1960 | + unsigned long ret; | |
| 1961 | + | |
| 1962 | + if (!cpumask_test_cpu(cpu, buffer->cpumask)) | |
| 1963 | + return 0; | |
| 1964 | + | |
| 1965 | + cpu_buffer = buffer->buffers[cpu]; | |
| 1966 | + ret = cpu_buffer->commit_overrun; | |
| 1967 | + | |
| 1968 | + return ret; | |
| 1969 | +} | |
| 1970 | +EXPORT_SYMBOL_GPL(ring_buffer_commit_overrun_cpu); | |
| 1971 | + | |
| 1928 | 1972 | /** |
| 1929 | 1973 | * ring_buffer_entries - get the number of entries in a buffer |
| 1930 | 1974 | * @buffer: The ring buffer |
| @@ -2595,6 +2639,8 @@ rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer) · 664 unmodified lines | ||
| 2595 | 2639 | local_set(&cpu_buffer->reader_page->page->commit, 0); |
| 2596 | 2640 | cpu_buffer->reader_page->read = 0; |
| 2597 | 2641 | |
| 2642 | + cpu_buffer->nmi_dropped = 0; | |
| 2643 | + cpu_buffer->commit_overrun = 0; | |
| 2598 | 2644 | cpu_buffer->overrun = 0; |
| 2599 | 2645 | cpu_buffer->entries = 0; |
| 2600 | 2646 | |