mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
tracing fixes for 7.2:
- Free field in error path of synthetic event parse In __create_synth_event() the field was allocated but was not freed in the error path. - Fix ring_buffer_event_length() on 8 byte aligned architectures On architectures with CONFIG_HAVE_64BIT_ALIGNED_ACCESS set to y, the ring_buffer_event_length() may return the wrong size. This is because archs with that config set will always use the "big event meta header" as that is 8 bytes keeping the payload 8 bytes aligned, even when a 4 byte header could hold the size of the event. But ring_buffer_event_length() doesn't take this into account and only subtracts 4 bytes for the meta header in the length when it should have subtracted 8 bytes. - Have osnoise wait for a full rcu synchronization on unregister osnoise_unregister_instance() used to call synchronize_rcu() before freeing its copy of the instance but was switched to kfree_rcu(). The osniose tracer has code that traverses the instances that it uses, and inst is just a pointer to that instance. By using kfree_rcu() instead of synchronize_rcu(), the instance that the inst pointer is pointing to can be freed while the osnoise code is still referencing it. That is, a rmdir on an instance first unregisters the tracer. When the unregister finishes, the rmdir expects that the tracer is finished with the instance that it is using. By putting back the synchronize_rcu() in osnoise_unregister_instance() the unregistering of osnoise will now return when all the users of the instance have finished. - Remove an unused setting of "ret" in tracing_set_tracer() - Fix ring_buffer_read_page() copying events The commit that changed ring_buffer_read_page() to show dropped events from the buffer itself, split the "commit" variable between the commit value (with flags) and "size" that holds the size of the sub-buffer. A cut and paste error changed the test of the reading from checking the size of the buffer to the size of the event causing reads to only read one event at a time. - Make tracepoint_printk a static variable When the tracing sysctl knobs were move from sysctl.c to trace.c, the variable tracepoint_printk no longer needed to be global. Make it static. - Fix some typos - Fix NULL pointer dereference in func_set_flag() The flags update of the function tracer first checks if the value of the flag is the same and exits if they are, and then it checks if the current tracer is the function tracer and exits if it isn't. The problem is that these checks need to be in a reversed order, as if the tracer isn't the function tracer, then the flag being checked may not exist. Reverse the order of these checks. - Fix ufs core trace events to not dereference a pointer in TP_printk() The TP_printk() part of the TRACE_EVENT() macro is called when the user reads the "trace" file. This can be seconds, minutes, hours, days, weeks, and even months after the data was recorded into the ring buffer. Thus, saving a pointer to an object into the ring buffer and then dereferencing it from TP_printk() can cause harm as the object the pointer is pointing to may no longer exist. Fix all the trace events in ufs core to save the device name in the ring buffer instead of dereferencing the device descriptor from TP_printk(). - Prevent out-of-bound reads in glob matching of trace events The filter logic of events allows simple glob logic to add wild cards to filter on strings. But some events have fields that may not have a terminating 'nul' character. This may cause the glob matching to go beyond the string. Change the logic to always pass in the length of the field that is being matched. - Add no-rcu-check version of trace_##event##_enabled() The trace_##event##_enabled() usually wraps trace events to do extra work that is only needed when the trace event is enabled. But this can hide events that are placed in locations where RCU is not watching, and can make lockdep not see these bugs when the event is not enabled. The trace_##event##_enabled() was updated to always test to make sure RCU is watching to catch locations that may call events without RCU being active. This caused a false positive for the irq_disabled() and related events. As that use trace_irq_disabled_enabled() to force RCU to be watching when the event is enabled via the ct_irq_enter() function, calls the event, and then calls ct_irq_exit() to put RCU back to its original state. The trace_irq_disabled_enabled() should not trigger a warning when RCU is not watching because the code within its block handles the case properly. Make a __trace_##event##_enabled() version for this event to use that doesn't check RCU is watching as it handles the case when it isn't. - Fix use-after-free in user_event_mm_dup() When the enabler is removed from the link list, it is freed immediately. But it is protected via RCU and needs to be freed after an RCU grace period. Use queue_rcu_work() so that the event_mutex can also be taken as user_event_put() takes the mutex on the last reference is released. - Free type string in error path of parse_synth_field() There's an error path in parse_synth_field() where the allocated type string is not freed. - Add selftest that tests deferred event teardown - Fix leak in error path of trace_remote_alloc_buffer() If page allocation fails, the desc->nr_cpus is not incremented for the current CPU and the allocations done for it are not freed. - Fix allocation length in trace_remote_alloc_buffer() The logic to calculate the struct_len was doing a double count and setting the value too large. Calculate the size upfront to fix the error and simplify the logic. - Fix sparse CPU masks in ring_buffer_desc() If there are sparse CPUs (gaps in the numbering), the ring_buffer_desc() will fail as it tests the CPU number against the number of CPUs that are used. -----BEGIN PGP SIGNATURE----- iQJIBAABCgAyFiEEXtmkj8VMCiLR0IBM68Js21pW3nMFAmpTv/cUHHJvc3RlZHRA Z29vZG1pcy5vcmcACgkQ68Js21pW3nN80w/9HEbliUUrJVNw8QCY8BmeBEzfCRhZ 2CeDzTg+UrLMb2BtqUhA9EjQnRPawe8mPxAfpZ750SdFnCkRhbfNwYmKar3M/8iW y2Bhsvd3Hz6nRiHvKhG/1RkflgKOWLYf/TQSByKlakYLV8t4uffa0fe0N0zcnikK XPGrhrTeRDJ7s94vb1u7p7mSSp2iy4ZhfXbagk966X3I4zvseIYNn5IIzyM3IIPT M7mE60SxvgSRz0QqTJqihmqjXYSeNOQ2iU18wnvp4QfcT0IVuLKm027JnK/YpjWS ZasMNGzO1kp5uo6hkXLrMlT3LjaNEMFTGogs1m9o9auhbMf443LK8GtZ1m1rwnTG cXn1PocBevQIaXWPbnxMrSwIuN7YMUqjgX6SCxbXpDxSSuE5i/x1VmE08CjxnSm6 TdAdom9bE44FvMgaAz9+KhIUgm013c2rFDNiFroYtfkma5FqpfnfglA4/TkJvexY e2L75cR3lrDEDiXXMQDndmvxNMhppwNlAH3mOZLiaCmGyFQFHhgAaG250K2Y6a5K HtIfJkT6RQ3rWifV0E0+zlyRiOrvVCCA8WwNArWb1dTWrVU86Hr7q58jAq9p0Yrz FnhpjdE3eWoUHZ5f28AMR2k5lMG3o6mOGT55JyUVCLw+rPSG5358UIg2xZiEo22k RFlT26FFHbMW50Y= =+//w -----END PGP SIGNATURE----- Merge tag 'trace-v7.2-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace Pull tracing fixes from Steven Rostedt: - Free field in error path of synthetic event parse In __create_synth_event() the field was allocated but was not freed in the error path - Fix ring_buffer_event_length() on 8 byte aligned architectures On architectures with CONFIG_HAVE_64BIT_ALIGNED_ACCESS set to y, the ring_buffer_event_length() may return the wrong size. This is because archs with that config set will always use the "big event meta header" as that is 8 bytes keeping the payload 8 bytes aligned, even when a 4 byte header could hold the size of the event But ring_buffer_event_length() doesn't take this into account and only subtracts 4 bytes for the meta header in the length when it should have subtracted 8 bytes - Have osnoise wait for a full rcu synchronization on unregister osnoise_unregister_instance() used to call synchronize_rcu() before freeing its copy of the instance but was switched to kfree_rcu(). The osniose tracer has code that traverses the instances that it uses, and inst is just a pointer to that instance. By using kfree_rcu() instead of synchronize_rcu(), the instance that the inst pointer is pointing to can be freed while the osnoise code is still referencing it That is, a rmdir on an instance first unregisters the tracer. When the unregister finishes, the rmdir expects that the tracer is finished with the instance that it is using. By putting back the synchronize_rcu() in osnoise_unregister_instance() the unregistering of osnoise will now return when all the users of the instance have finished - Remove an unused setting of "ret" in tracing_set_tracer() - Fix ring_buffer_read_page() copying events The commit that changed ring_buffer_read_page() to show dropped events from the buffer itself, split the "commit" variable between the commit value (with flags) and "size" that holds the size of the sub-buffer. A cut and paste error changed the test of the reading from checking the size of the buffer to the size of the event causing reads to only read one event at a time - Make tracepoint_printk a static variable When the tracing sysctl knobs were move from sysctl.c to trace.c, the variable tracepoint_printk no longer needed to be global. Make it static - Fix some typos - Fix NULL pointer dereference in func_set_flag() The flags update of the function tracer first checks if the value of the flag is the same and exits if they are, and then it checks if the current tracer is the function tracer and exits if it isn't. The problem is that these checks need to be in a reversed order, as if the tracer isn't the function tracer, then the flag being checked may not exist. Reverse the order of these checks - Fix ufs core trace events to not dereference a pointer in TP_printk() The TP_printk() part of the TRACE_EVENT() macro is called when the user reads the "trace" file. This can be seconds, minutes, hours, days, weeks, and even months after the data was recorded into the ring buffer. Thus, saving a pointer to an object into the ring buffer and then dereferencing it from TP_printk() can cause harm as the object the pointer is pointing to may no longer exist Fix all the trace events in ufs core to save the device name in the ring buffer instead of dereferencing the device descriptor from TP_printk() - Prevent out-of-bound reads in glob matching of trace events The filter logic of events allows simple glob logic to add wild cards to filter on strings. But some events have fields that may not have a terminating 'nul' character. This may cause the glob matching to go beyond the string. Change the logic to always pass in the length of the field that is being matched - Add no-rcu-check version of trace_##event##_enabled() The trace_##event##_enabled() usually wraps trace events to do extra work that is only needed when the trace event is enabled. But this can hide events that are placed in locations where RCU is not watching, and can make lockdep not see these bugs when the event is not enabled The trace_##event##_enabled() was updated to always test to make sure RCU is watching to catch locations that may call events without RCU being active This caused a false positive for the irq_disabled() and related events. As that use trace_irq_disabled_enabled() to force RCU to be watching when the event is enabled via the ct_irq_enter() function, calls the event, and then calls ct_irq_exit() to put RCU back to its original state The trace_irq_disabled_enabled() should not trigger a warning when RCU is not watching because the code within its block handles the case properly. Make a __trace_##event##_enabled() version for this event to use that doesn't check RCU is watching as it handles the case when it isn't - Fix use-after-free in user_event_mm_dup() When the enabler is removed from the link list, it is freed immediately. But it is protected via RCU and needs to be freed after an RCU grace period. Use queue_rcu_work() so that the event_mutex can also be taken as user_event_put() takes the mutex on the last reference is released - Free type string in error path of parse_synth_field() There's an error path in parse_synth_field() where the allocated type string is not freed - Add selftest that tests deferred event teardown - Fix leak in error path of trace_remote_alloc_buffer() If page allocation fails, the desc->nr_cpus is not incremented for the current CPU and the allocations done for it are not freed - Fix allocation length in trace_remote_alloc_buffer() The logic to calculate the struct_len was doing a double count and setting the value too large. Calculate the size upfront to fix the error and simplify the logic - Fix sparse CPU masks in ring_buffer_desc() If there are sparse CPUs (gaps in the numbering), the ring_buffer_desc() will fail as it tests the CPU number against the number of CPUs that are used * tag 'trace-v7.2-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: ring-buffer: Allow sparse CPU masks in ring_buffer_desc() tracing/remotes: Fix struct_len in trace_remote_alloc_buffer() tracing/remotes: Fix leak in trace_remote_alloc_buffer() error path selftests/user_events: Wait for deferred event teardown after unregister tracing/synthetic: Free type string on error path tracing/user_events: Fix use-after-free in user_event_mm_dup() tracing: Add a no-rcu-check version of trace_##event##_enabled() tracing: Prevent out-of-bounds read in glob matching ufs: core: tracing: Do not dereference pointers in TP_printk() tracing: Fix NULL pointer dereference in func_set_flag() samples: ftrace: Fix typos in benchmark comment tracing: Make tracepoint_printk static as not exported ring-buffer: Fix ring_buffer_read_page() copying only one event per page tracing: Remove unused ret assignment in tracing_set_tracer() tracing/osnoise: Call synchronize_rcu() when unregistering ring-buffer: Fix event length with forced 8-byte alignment tracing/synthetic: Free pending field on error path
This commit is contained in:
commit
6205562c59
|
|
@ -89,16 +89,18 @@ TRACE_EVENT(ufshcd_clk_gating,
|
|||
|
||||
TP_STRUCT__entry(
|
||||
__field(struct ufs_hba *, hba)
|
||||
__string(dev_name, dev_name(hba->dev))
|
||||
__field(int, state)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(dev_name);
|
||||
__entry->hba = hba;
|
||||
__entry->state = state;
|
||||
),
|
||||
|
||||
TP_printk("%s: gating state changed to %s",
|
||||
dev_name(__entry->hba->dev),
|
||||
__get_str(dev_name),
|
||||
__print_symbolic(__entry->state, UFSCHD_CLK_GATING_STATES))
|
||||
);
|
||||
|
||||
|
|
@ -111,6 +113,7 @@ TRACE_EVENT(ufshcd_clk_scaling,
|
|||
|
||||
TP_STRUCT__entry(
|
||||
__field(struct ufs_hba *, hba)
|
||||
__string(dev_name, dev_name(hba->dev))
|
||||
__string(state, state)
|
||||
__string(clk, clk)
|
||||
__field(u32, prev_state)
|
||||
|
|
@ -119,6 +122,7 @@ TRACE_EVENT(ufshcd_clk_scaling,
|
|||
|
||||
TP_fast_assign(
|
||||
__entry->hba = hba;
|
||||
__assign_str(dev_name);
|
||||
__assign_str(state);
|
||||
__assign_str(clk);
|
||||
__entry->prev_state = prev_state;
|
||||
|
|
@ -126,7 +130,7 @@ TRACE_EVENT(ufshcd_clk_scaling,
|
|||
),
|
||||
|
||||
TP_printk("%s: %s %s from %u to %u Hz",
|
||||
dev_name(__entry->hba->dev), __get_str(state), __get_str(clk),
|
||||
__get_str(dev_name), __get_str(state), __get_str(clk),
|
||||
__entry->prev_state, __entry->curr_state)
|
||||
);
|
||||
|
||||
|
|
@ -138,16 +142,18 @@ TRACE_EVENT(ufshcd_auto_bkops_state,
|
|||
|
||||
TP_STRUCT__entry(
|
||||
__field(struct ufs_hba *, hba)
|
||||
__string(dev_name, dev_name(hba->dev))
|
||||
__string(state, state)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->hba = hba;
|
||||
__assign_str(dev_name);
|
||||
__assign_str(state);
|
||||
),
|
||||
|
||||
TP_printk("%s: auto bkops - %s",
|
||||
dev_name(__entry->hba->dev), __get_str(state))
|
||||
__get_str(dev_name), __get_str(state))
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(ufshcd_profiling_template,
|
||||
|
|
@ -158,6 +164,7 @@ DECLARE_EVENT_CLASS(ufshcd_profiling_template,
|
|||
|
||||
TP_STRUCT__entry(
|
||||
__field(struct ufs_hba *, hba)
|
||||
__string(dev_name, dev_name(hba->dev))
|
||||
__string(profile_info, profile_info)
|
||||
__field(s64, time_us)
|
||||
__field(int, err)
|
||||
|
|
@ -165,13 +172,14 @@ DECLARE_EVENT_CLASS(ufshcd_profiling_template,
|
|||
|
||||
TP_fast_assign(
|
||||
__entry->hba = hba;
|
||||
__assign_str(dev_name);
|
||||
__assign_str(profile_info);
|
||||
__entry->time_us = time_us;
|
||||
__entry->err = err;
|
||||
),
|
||||
|
||||
TP_printk("%s: %s: took %lld usecs, err %d",
|
||||
dev_name(__entry->hba->dev), __get_str(profile_info),
|
||||
__get_str(dev_name), __get_str(profile_info),
|
||||
__entry->time_us, __entry->err)
|
||||
);
|
||||
|
||||
|
|
@ -200,6 +208,7 @@ DECLARE_EVENT_CLASS(ufshcd_template,
|
|||
__field(s64, usecs)
|
||||
__field(int, err)
|
||||
__field(struct ufs_hba *, hba)
|
||||
__string(dev_name, dev_name(hba->dev))
|
||||
__field(int, dev_state)
|
||||
__field(int, link_state)
|
||||
),
|
||||
|
|
@ -208,13 +217,14 @@ DECLARE_EVENT_CLASS(ufshcd_template,
|
|||
__entry->usecs = usecs;
|
||||
__entry->err = err;
|
||||
__entry->hba = hba;
|
||||
__assign_str(dev_name);
|
||||
__entry->dev_state = dev_state;
|
||||
__entry->link_state = link_state;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"%s: took %lld usecs, dev_state: %s, link_state: %s, err %d",
|
||||
dev_name(__entry->hba->dev),
|
||||
__get_str(dev_name),
|
||||
__entry->usecs,
|
||||
__print_symbolic(__entry->dev_state, UFS_PWR_MODES),
|
||||
__print_symbolic(__entry->link_state, UFS_LINK_STATES),
|
||||
|
|
@ -279,6 +289,7 @@ TRACE_EVENT(ufshcd_command,
|
|||
TP_STRUCT__entry(
|
||||
__field(struct scsi_device *, sdev)
|
||||
__field(struct ufs_hba *, hba)
|
||||
__string(dev_name, dev_name(&sdev->sdev_dev))
|
||||
__field(enum ufs_trace_str_t, str_t)
|
||||
__field(unsigned int, tag)
|
||||
__field(u32, doorbell)
|
||||
|
|
@ -291,6 +302,7 @@ TRACE_EVENT(ufshcd_command,
|
|||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(dev_name);
|
||||
__entry->sdev = sdev;
|
||||
__entry->hba = hba;
|
||||
__entry->str_t = str_t;
|
||||
|
|
@ -307,7 +319,7 @@ TRACE_EVENT(ufshcd_command,
|
|||
TP_printk(
|
||||
"%s: %s: tag: %u, DB: 0x%x, size: %d, IS: %u, LBA: %llu, opcode: 0x%x (%s), group_id: 0x%x, hwq_id: %d",
|
||||
show_ufs_cmd_trace_str(__entry->str_t),
|
||||
dev_name(&__entry->sdev->sdev_dev), __entry->tag,
|
||||
__get_str(dev_name), __entry->tag,
|
||||
__entry->doorbell, __entry->transfer_len, __entry->intr,
|
||||
__entry->lba, (u32)__entry->opcode, str_opcode(__entry->opcode),
|
||||
(u32)__entry->group_id, __entry->hwq_id
|
||||
|
|
@ -322,6 +334,7 @@ TRACE_EVENT(ufshcd_uic_command,
|
|||
|
||||
TP_STRUCT__entry(
|
||||
__field(struct ufs_hba *, hba)
|
||||
__string(dev_name, dev_name(hba->dev))
|
||||
__field(enum ufs_trace_str_t, str_t)
|
||||
__field(u32, cmd)
|
||||
__field(u32, arg1)
|
||||
|
|
@ -331,6 +344,7 @@ TRACE_EVENT(ufshcd_uic_command,
|
|||
|
||||
TP_fast_assign(
|
||||
__entry->hba = hba;
|
||||
__assign_str(dev_name);
|
||||
__entry->str_t = str_t;
|
||||
__entry->cmd = cmd;
|
||||
__entry->arg1 = arg1;
|
||||
|
|
@ -340,7 +354,7 @@ TRACE_EVENT(ufshcd_uic_command,
|
|||
|
||||
TP_printk(
|
||||
"%s: %s: cmd: 0x%x, arg1: 0x%x, arg2: 0x%x, arg3: 0x%x",
|
||||
show_ufs_cmd_trace_str(__entry->str_t), dev_name(__entry->hba->dev),
|
||||
show_ufs_cmd_trace_str(__entry->str_t), __get_str(dev_name),
|
||||
__entry->cmd, __entry->arg1, __entry->arg2, __entry->arg3
|
||||
)
|
||||
);
|
||||
|
|
@ -353,6 +367,7 @@ TRACE_EVENT(ufshcd_upiu,
|
|||
|
||||
TP_STRUCT__entry(
|
||||
__field(struct ufs_hba *, hba)
|
||||
__string(dev_name, dev_name(hba->dev))
|
||||
__field(enum ufs_trace_str_t, str_t)
|
||||
__array(unsigned char, hdr, 12)
|
||||
__array(unsigned char, tsf, 16)
|
||||
|
|
@ -361,6 +376,7 @@ TRACE_EVENT(ufshcd_upiu,
|
|||
|
||||
TP_fast_assign(
|
||||
__entry->hba = hba;
|
||||
__assign_str(dev_name);
|
||||
__entry->str_t = str_t;
|
||||
memcpy(__entry->hdr, hdr, sizeof(__entry->hdr));
|
||||
memcpy(__entry->tsf, tsf, sizeof(__entry->tsf));
|
||||
|
|
@ -369,7 +385,7 @@ TRACE_EVENT(ufshcd_upiu,
|
|||
|
||||
TP_printk(
|
||||
"%s: %s: HDR:%s, %s:%s",
|
||||
show_ufs_cmd_trace_str(__entry->str_t), dev_name(__entry->hba->dev),
|
||||
show_ufs_cmd_trace_str(__entry->str_t), __get_str(dev_name),
|
||||
__print_hex(__entry->hdr, sizeof(__entry->hdr)),
|
||||
show_ufs_cmd_trace_tsf(__entry->tsf_t),
|
||||
__print_hex(__entry->tsf, sizeof(__entry->tsf))
|
||||
|
|
@ -384,16 +400,18 @@ TRACE_EVENT(ufshcd_exception_event,
|
|||
|
||||
TP_STRUCT__entry(
|
||||
__field(struct ufs_hba *, hba)
|
||||
__string(dev_name, dev_name(hba->dev))
|
||||
__field(u16, status)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->hba = hba;
|
||||
__assign_str(dev_name);
|
||||
__entry->status = status;
|
||||
),
|
||||
|
||||
TP_printk("%s: status 0x%x",
|
||||
dev_name(__entry->hba->dev), __entry->status
|
||||
__get_str(dev_name), __entry->status
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,5 +6,6 @@
|
|||
#include <linux/compiler.h> /* For __pure */
|
||||
|
||||
bool __pure glob_match(char const *pat, char const *str);
|
||||
bool __pure glob_match_len(char const *pat, char const *str, size_t len);
|
||||
|
||||
#endif /* _LINUX_GLOB_H */
|
||||
|
|
|
|||
|
|
@ -292,13 +292,18 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
|
|||
{ \
|
||||
} \
|
||||
static inline bool \
|
||||
__trace_##name##_enabled(void) \
|
||||
{ \
|
||||
return static_branch_unlikely(&__tracepoint_##name.key);\
|
||||
} \
|
||||
static inline bool \
|
||||
trace_##name##_enabled(void) \
|
||||
{ \
|
||||
if (IS_ENABLED(CONFIG_LOCKDEP)) { \
|
||||
WARN_ONCE(!rcu_is_watching(), \
|
||||
"RCU not watching for tracepoint"); \
|
||||
} \
|
||||
return static_branch_unlikely(&__tracepoint_##name.key);\
|
||||
return __trace_##name##_enabled(); \
|
||||
}
|
||||
|
||||
#define __DECLARE_TRACE(name, proto, args, cond, data_proto) \
|
||||
|
|
@ -457,6 +462,11 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
|
|||
{ \
|
||||
} \
|
||||
static inline bool \
|
||||
__trace_##name##_enabled(void) \
|
||||
{ \
|
||||
return false; \
|
||||
} \
|
||||
static inline bool \
|
||||
trace_##name##_enabled(void) \
|
||||
{ \
|
||||
return false; \
|
||||
|
|
|
|||
|
|
@ -270,7 +270,8 @@ unsigned ring_buffer_event_length(struct ring_buffer_event *event)
|
|||
if (event->type_len > RINGBUF_TYPE_DATA_TYPE_LEN_MAX)
|
||||
return length;
|
||||
length -= RB_EVNT_HDR_SIZE;
|
||||
if (length > RB_MAX_SMALL_DATA + sizeof(event->array[0]))
|
||||
if (length > RB_MAX_SMALL_DATA + sizeof(event->array[0]) ||
|
||||
RB_FORCE_8BYTE_ALIGNMENT)
|
||||
length -= sizeof(event->array[0]);
|
||||
return length;
|
||||
}
|
||||
|
|
@ -2329,10 +2330,7 @@ static struct ring_buffer_desc *ring_buffer_desc(struct trace_buffer_desc *trace
|
|||
size_t len;
|
||||
int i;
|
||||
|
||||
if (!trace_desc)
|
||||
return NULL;
|
||||
|
||||
if (cpu >= trace_desc->nr_cpus)
|
||||
if (!trace_desc || !trace_desc->nr_cpus)
|
||||
return NULL;
|
||||
|
||||
end = (struct ring_buffer_desc *)((void *)trace_desc + trace_desc->struct_len);
|
||||
|
|
@ -7174,7 +7172,7 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
|
|||
rpos = reader->read;
|
||||
pos += event_size;
|
||||
|
||||
if (rpos >= event_size)
|
||||
if (rpos >= size)
|
||||
break;
|
||||
|
||||
event = rb_reader_event(cpu_buffer);
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ void __init disable_tracing_selftest(const char *reason)
|
|||
|
||||
/* Pipe tracepoints to printk */
|
||||
static struct trace_iterator *tracepoint_print_iter;
|
||||
int tracepoint_printk;
|
||||
static int tracepoint_printk;
|
||||
static bool tracepoint_printk_stop_on_boot __initdata;
|
||||
static bool traceoff_after_boot __initdata;
|
||||
static DEFINE_STATIC_KEY_FALSE(tracepoint_printk_key);
|
||||
|
|
@ -5015,7 +5015,6 @@ int tracing_set_tracer(struct trace_array *tr, const char *buf)
|
|||
RING_BUFFER_ALL_CPUS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
list_for_each_entry(t, &tr->tracers, list) {
|
||||
|
|
|
|||
|
|
@ -1056,11 +1056,9 @@ static int regex_match_end(char *str, struct regex *r, int len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int regex_match_glob(char *str, struct regex *r, int len __maybe_unused)
|
||||
static int regex_match_glob(char *str, struct regex *r, int len)
|
||||
{
|
||||
if (glob_match(r->pattern, str))
|
||||
return 1;
|
||||
return 0;
|
||||
return glob_match_len(r->pattern, str, len) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -839,8 +839,10 @@ static struct synth_field *parse_synth_field(int argc, char **argv,
|
|||
seq_buf_puts(&s, "__data_loc ");
|
||||
seq_buf_puts(&s, field->type);
|
||||
|
||||
if (WARN_ON_ONCE(!seq_buf_buffer_left(&s)))
|
||||
if (WARN_ON_ONCE(!seq_buf_buffer_left(&s))) {
|
||||
kfree(type);
|
||||
goto free;
|
||||
}
|
||||
s.buffer[s.len] = '\0';
|
||||
|
||||
kfree(field->type);
|
||||
|
|
@ -1446,13 +1448,13 @@ static int __create_synth_event(const char *name, const char *raw_fields)
|
|||
if (cmd_version > 1 && n_fields_this_loop >= 1) {
|
||||
synth_err(SYNTH_ERR_INVALID_CMD, errpos(field_str));
|
||||
ret = -EINVAL;
|
||||
goto err_free_arg;
|
||||
goto err_free_field;
|
||||
}
|
||||
|
||||
if (n_fields == SYNTH_FIELDS_MAX) {
|
||||
synth_err(SYNTH_ERR_TOO_MANY_FIELDS, 0);
|
||||
ret = -EINVAL;
|
||||
goto err_free_arg;
|
||||
goto err_free_field;
|
||||
}
|
||||
fields[n_fields++] = field;
|
||||
|
||||
|
|
@ -1491,6 +1493,8 @@ static int __create_synth_event(const char *name, const char *raw_fields)
|
|||
kfree(saved_fields);
|
||||
|
||||
return ret;
|
||||
err_free_field:
|
||||
free_synth_field(field);
|
||||
err_free_arg:
|
||||
argv_free(argv);
|
||||
err:
|
||||
|
|
|
|||
|
|
@ -109,6 +109,9 @@ struct user_event_enabler {
|
|||
|
||||
/* Track enable bit, flags, etc. Aligned for bitops. */
|
||||
unsigned long values;
|
||||
|
||||
/* Defer the event put and enabler free past an RCU grace period. */
|
||||
struct rcu_work put_rwork;
|
||||
};
|
||||
|
||||
/* Bits 0-5 are for the bit to update upon enable/disable (0-63 allowed) */
|
||||
|
|
@ -396,15 +399,37 @@ static struct user_event_group *user_event_group_create(void)
|
|||
return NULL;
|
||||
};
|
||||
|
||||
static void user_event_enabler_destroy(struct user_event_enabler *enabler,
|
||||
bool locked)
|
||||
static void delayed_user_event_enabler_put(struct work_struct *work)
|
||||
{
|
||||
struct user_event_enabler *enabler = container_of(to_rcu_work(work),
|
||||
struct user_event_enabler, put_rwork);
|
||||
|
||||
/* No longer tracking the event via the enabler */
|
||||
user_event_put(enabler->event, false);
|
||||
|
||||
/* Run from queue_rcu_work(), the RCU grace period has elapsed */
|
||||
kfree(enabler);
|
||||
}
|
||||
|
||||
static void user_event_enabler_destroy(struct user_event_enabler *enabler)
|
||||
{
|
||||
list_del_rcu(&enabler->mm_enablers_link);
|
||||
|
||||
/* No longer tracking the event via the enabler */
|
||||
user_event_put(enabler->event, locked);
|
||||
|
||||
kfree(enabler);
|
||||
/*
|
||||
* The enabler is removed from an RCU-traversed list
|
||||
* (user_event_mm_dup() walks mm->enablers under rcu_read_lock() only),
|
||||
* and readers there dereference enabler->event and take a new ref on
|
||||
* it. Both the put of that event reference and the free of the enabler
|
||||
* therefore have to wait for a grace period so no reader can be looking
|
||||
* at the enabler or racing the last put of its event.
|
||||
*
|
||||
* The put itself must not run in RCU context: when it drops the last
|
||||
* reference user_event_put() takes event_mutex, which cannot be taken
|
||||
* from a softirq/RCU callback. Defer both to a work item scheduled
|
||||
* after a grace period via queue_rcu_work().
|
||||
*/
|
||||
INIT_RCU_WORK(&enabler->put_rwork, delayed_user_event_enabler_put);
|
||||
queue_rcu_work(system_percpu_wq, &enabler->put_rwork);
|
||||
}
|
||||
|
||||
static int user_event_mm_fault_in(struct user_event_mm *mm, unsigned long uaddr,
|
||||
|
|
@ -464,7 +489,7 @@ static void user_event_enabler_fault_fixup(struct work_struct *work)
|
|||
|
||||
/* User asked for enabler to be removed during fault */
|
||||
if (test_bit(ENABLE_VAL_FREEING_BIT, ENABLE_BITOPS(enabler))) {
|
||||
user_event_enabler_destroy(enabler, true);
|
||||
user_event_enabler_destroy(enabler);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -764,7 +789,7 @@ static void user_event_mm_destroy(struct user_event_mm *mm)
|
|||
struct user_event_enabler *enabler, *next;
|
||||
|
||||
list_for_each_entry_safe(enabler, next, &mm->enablers, mm_enablers_link)
|
||||
user_event_enabler_destroy(enabler, false);
|
||||
user_event_enabler_destroy(enabler);
|
||||
|
||||
mmdrop(mm->mm);
|
||||
kfree(mm);
|
||||
|
|
@ -2645,7 +2670,7 @@ static long user_events_ioctl_unreg(unsigned long uarg)
|
|||
flags |= enabler->values & ENABLE_VAL_COMPAT_MASK;
|
||||
|
||||
if (!test_bit(ENABLE_VAL_FAULTING_BIT, ENABLE_BITOPS(enabler)))
|
||||
user_event_enabler_destroy(enabler, true);
|
||||
user_event_enabler_destroy(enabler);
|
||||
|
||||
/* Removed at least one */
|
||||
ret = 0;
|
||||
|
|
|
|||
|
|
@ -458,12 +458,12 @@ func_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
|
|||
ftrace_func_t func;
|
||||
u32 new_flags;
|
||||
|
||||
/* Do nothing if already set. */
|
||||
if (!!set == !!(tr->current_trace_flags->val & bit))
|
||||
/* We can change this flag only when current tracer is function. */
|
||||
if (tr->current_trace != &function_trace)
|
||||
return 0;
|
||||
|
||||
/* We can change this flag only when not running. */
|
||||
if (tr->current_trace != &function_trace)
|
||||
/* Do nothing if already set. */
|
||||
if (!!set == !!(tr->current_trace_flags->val & bit))
|
||||
return 0;
|
||||
|
||||
new_flags = (tr->current_trace_flags->val & ~bit) | (set ? bit : 0);
|
||||
|
|
|
|||
|
|
@ -179,7 +179,9 @@ static void osnoise_unregister_instance(struct trace_array *tr)
|
|||
if (!found)
|
||||
return;
|
||||
|
||||
kvfree_rcu_mightsleep(inst);
|
||||
/* Do a full sync to ensure that tr remains valid, not just inst */
|
||||
synchronize_rcu();
|
||||
kvfree(inst);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
#else
|
||||
#define trace(point, args) \
|
||||
do { \
|
||||
if (trace_##point##_enabled()) { \
|
||||
if (__trace_##point##_enabled()) { \
|
||||
bool exit_rcu = false; \
|
||||
if (in_nmi()) \
|
||||
break; \
|
||||
|
|
|
|||
|
|
@ -979,33 +979,30 @@ EXPORT_SYMBOL_GPL(trace_remote_free_buffer);
|
|||
int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t desc_size, size_t buffer_size,
|
||||
const struct cpumask *cpumask)
|
||||
{
|
||||
size_t min_desc_size = trace_buffer_desc_size(buffer_size, cpumask_weight(cpumask));
|
||||
unsigned int nr_pages = max(DIV_ROUND_UP(buffer_size, PAGE_SIZE), 2UL) + 1;
|
||||
void *desc_end = desc + desc_size;
|
||||
struct ring_buffer_desc *rb_desc;
|
||||
int cpu, ret = -ENOMEM;
|
||||
|
||||
if (desc_size < struct_size(desc, __data, 0))
|
||||
if (desc_size < min_desc_size)
|
||||
return -EINVAL;
|
||||
|
||||
desc->nr_cpus = 0;
|
||||
desc->struct_len = struct_size(desc, __data, 0);
|
||||
desc->struct_len = min_desc_size;
|
||||
|
||||
rb_desc = (struct ring_buffer_desc *)&desc->__data[0];
|
||||
rb_desc = __first_ring_buffer_desc(desc);
|
||||
|
||||
for_each_cpu(cpu, cpumask) {
|
||||
unsigned int id;
|
||||
|
||||
if ((void *)rb_desc + struct_size(rb_desc, page_va, nr_pages) > desc_end) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
rb_desc->cpu = cpu;
|
||||
rb_desc->nr_page_va = 0;
|
||||
rb_desc->meta_va = (unsigned long)__get_free_page(GFP_KERNEL);
|
||||
if (!rb_desc->meta_va)
|
||||
goto err;
|
||||
|
||||
desc->nr_cpus++;
|
||||
|
||||
for (id = 0; id < nr_pages; id++) {
|
||||
rb_desc->page_va[id] = (unsigned long)__get_free_page(GFP_KERNEL);
|
||||
if (!rb_desc->page_va[id])
|
||||
|
|
@ -1013,9 +1010,6 @@ int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t desc_size,
|
|||
|
||||
rb_desc->nr_page_va++;
|
||||
}
|
||||
desc->nr_cpus++;
|
||||
desc->struct_len += offsetof(struct ring_buffer_desc, page_va);
|
||||
desc->struct_len += struct_size(rb_desc, page_va, rb_desc->nr_page_va);
|
||||
rb_desc = __next_ring_buffer_desc(rb_desc);
|
||||
}
|
||||
|
||||
|
|
|
|||
31
lib/glob.c
31
lib/glob.c
|
|
@ -11,6 +11,9 @@
|
|||
MODULE_DESCRIPTION("glob(7) matching");
|
||||
MODULE_LICENSE("Dual MIT/GPL");
|
||||
|
||||
static bool __pure glob_match_str(char const *pat, char const *str,
|
||||
char const *str_end);
|
||||
|
||||
/**
|
||||
* glob_match - Shell-style pattern matching, like !fnmatch(pat, str, 0)
|
||||
* @pat: Shell-style pattern to match, e.g. "*.[ch]".
|
||||
|
|
@ -40,6 +43,29 @@ MODULE_LICENSE("Dual MIT/GPL");
|
|||
* An opening bracket without a matching close is matched literally.
|
||||
*/
|
||||
bool __pure glob_match(char const *pat, char const *str)
|
||||
{
|
||||
return glob_match_str(pat, str, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(glob_match);
|
||||
|
||||
/**
|
||||
* glob_match_len - glob match against a length-bounded string
|
||||
* @pat: Shell-style pattern to match.
|
||||
* @str: String to match. Need not be NUL-terminated.
|
||||
* @len: Number of bytes of @str that may be read.
|
||||
*
|
||||
* Like glob_match(), but @str is only read up to @len bytes, so it can be
|
||||
* used on buffers that are not NUL-terminated (e.g. trace event fields).
|
||||
* A NUL byte within @len still terminates the string.
|
||||
*/
|
||||
bool __pure glob_match_len(char const *pat, char const *str, size_t len)
|
||||
{
|
||||
return glob_match_str(pat, str, str + len);
|
||||
}
|
||||
EXPORT_SYMBOL(glob_match_len);
|
||||
|
||||
static bool __pure glob_match_str(char const *pat, char const *str,
|
||||
char const *str_end)
|
||||
{
|
||||
/*
|
||||
* Backtrack to previous * on mismatch and retry starting one
|
||||
|
|
@ -55,9 +81,11 @@ bool __pure glob_match(char const *pat, char const *str)
|
|||
* on mismatch, or true after matching the trailing nul bytes.
|
||||
*/
|
||||
for (;;) {
|
||||
unsigned char c = *str++;
|
||||
unsigned char c = (str_end && str >= str_end) ? '\0' : *str;
|
||||
unsigned char d = *pat++;
|
||||
|
||||
str++;
|
||||
|
||||
switch (d) {
|
||||
case '?': /* Wildcard: anything but nul */
|
||||
if (c == '\0')
|
||||
|
|
@ -125,4 +153,3 @@ bool __pure glob_match(char const *pat, char const *str)
|
|||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(glob_match);
|
||||
|
|
|
|||
|
|
@ -232,8 +232,8 @@ static int __init ftrace_ops_sample_init(void)
|
|||
ops_destroy(ops_irrelevant, nr_ops_irrelevant);
|
||||
|
||||
/*
|
||||
* The benchmark completed sucessfully, but there's no reason to keep
|
||||
* the module around. Return an error do the user doesn't have to
|
||||
* The benchmark completed successfully, but there's no reason to keep
|
||||
* the module around. Return an error so the user doesn't have to
|
||||
* manually unload the module.
|
||||
*/
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -132,6 +132,33 @@ static int event_delete(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deleting an event drops its last reference, but an unregister may defer
|
||||
* that put (and the freeing of the associated enabler) past an RCU grace
|
||||
* period. The delete can therefore transiently fail with -EBUSY while the
|
||||
* previous reference is still being dropped. Retry only on that transient
|
||||
* failure; treat an already-deleted event (-ENOENT) as success and return
|
||||
* any other error immediately rather than spinning for the full timeout.
|
||||
*/
|
||||
static int wait_for_event_delete(void)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < 10000; ++i) {
|
||||
ret = event_delete();
|
||||
|
||||
if (ret == 0 || errno == ENOENT)
|
||||
return 0;
|
||||
|
||||
if (errno != EBUSY)
|
||||
return ret;
|
||||
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int reg_enable_multi(void *enable, int size, int bit, int flags,
|
||||
char *args)
|
||||
{
|
||||
|
|
@ -262,7 +289,7 @@ TEST_F(user, flags) {
|
|||
ASSERT_TRUE(event_exists());
|
||||
|
||||
/* Ensure we can delete it */
|
||||
ASSERT_EQ(0, event_delete());
|
||||
ASSERT_EQ(0, wait_for_event_delete());
|
||||
|
||||
/* USER_EVENT_REG_MAX or above is not allowed */
|
||||
ASSERT_EQ(-1, reg_enable_flags(&self->check, sizeof(int), 0,
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ static int get_offset(void)
|
|||
static int clear(int *check)
|
||||
{
|
||||
struct user_unreg unreg = {0};
|
||||
int i, ret;
|
||||
|
||||
unreg.size = sizeof(unreg);
|
||||
unreg.disable_bit = 31;
|
||||
|
|
@ -99,13 +100,32 @@ static int clear(int *check)
|
|||
if (errno != ENOENT)
|
||||
return -1;
|
||||
|
||||
if (ioctl(fd, DIAG_IOCSDEL, "__test_event") == -1)
|
||||
if (errno != ENOENT)
|
||||
/*
|
||||
* Deleting the event drops its last reference, but the unregister
|
||||
* above defers that put (and the freeing of the enabler) past an RCU
|
||||
* grace period. The delete can therefore transiently fail with -EBUSY
|
||||
* until that reference is dropped. Retry for up to ~10 seconds so the
|
||||
* event is actually gone before the next test registers the same name.
|
||||
*/
|
||||
for (i = 0; i < 10000; ++i) {
|
||||
ret = ioctl(fd, DIAG_IOCSDEL, "__test_event");
|
||||
|
||||
if (ret == 0 || errno == ENOENT) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (errno != EBUSY) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
FIXTURE(user) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user