[RFC] mm/vmscan.c: avoid possible long latency caused by too_many_isolated()
From: Zhengjun Xing In the system with very few file pages, it is easy to reproduce "nr_isolated_file > nr_inactive_file", then too_many_isolated return true, shrink_inactive_list enter "msleep(100)", the long latency will happen. The test case to reproduce it is very simple, allocate a lot of huge pages (near the DRAM size), then do free, repeat the same operation many times. There is a 3/10 rate to reproduce the issue. In the test, sc-> gfp_mask is 0x342cca ("_GFP_IO" and "__GFP_FS" is masked),it is more easy to enter “inactive >>=3”, then “isolated > inactive” will easy to be true. So I have a proposal to set a threshold number for the total file pages to ignore the system with very few file pages, and then bypass the 100ms sleep. It is hard to set a perfect number for the threshold, so I just give an example of "256" for it, need more inputs for it. Signed-off-by: Zhengjun Xing --- mm/vmscan.c | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index 562e87cbd7a1..a1926463455c 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -168,6 +168,7 @@ struct scan_control { * From 0 .. 200. Higher means more swappy. */ int vm_swappiness = 60; +int lru_list_threshold = SWAP_CLUSTER_MAX << 3; static void set_task_reclaim_state(struct task_struct *task, struct reclaim_state *rs) @@ -1785,7 +1786,7 @@ int isolate_lru_page(struct page *page) static int too_many_isolated(struct pglist_data *pgdat, int file, struct scan_control *sc) { - unsigned long inactive, isolated; + unsigned long inactive, isolated, active, nr_lru_pages; if (current_is_kswapd()) return 0; @@ -1796,11 +1797,13 @@ static int too_many_isolated(struct pglist_data *pgdat, int file, if (file) { inactive = node_page_state(pgdat, NR_INACTIVE_FILE); isolated = node_page_state(pgdat, NR_ISOLATED_FILE); + active = node_page_state(pgdat, NR_ACTIVE_FILE); } else { inactive = node_page_state(pgdat, NR_INACTIVE_ANON); isolated = node_page_state(pgdat, NR_ISOLATED_ANON); + active = node_page_state(pgdat, NR_ACTIVE_ANON); } - + nr_lru_pages = inactive + active; /* * GFP_NOIO/GFP_NOFS callers are allowed to isolate more pages, so they * won't get blocked by normal direct-reclaimers, forming a circular @@ -1809,6 +1812,10 @@ static int too_many_isolated(struct pglist_data *pgdat, int file, if ((sc->gfp_mask & (__GFP_IO | __GFP_FS)) == (__GFP_IO | __GFP_FS)) inactive >>= 3; + if (isolated > inactive) + if (nr_lru_pages < lru_list_threshold) + return 0; + return isolated > inactive; } -- 2.17.1
[PATCH v2] tracing: fix "gfp_t" format for synthetic events
In the format of synthetic events, the "gfp_t" is shown as "signed:1", but in fact the "gfp_t" is "unsigned", should be shown as "signed:0". The issue can be reproduced by the following commands: echo 'memlatency u64 lat; unsigned int order; gfp_t gfp_flags; int migratetype' > /sys/kernel/debug/tracing/synthetic_events cat /sys/kernel/debug/tracing/events/synthetic/memlatency/format name: memlatency ID: 2233 format: field:unsigned short common_type; offset:0; size:2; signed:0; field:unsigned char common_flags; offset:2; size:1; signed:0; field:unsigned char common_preempt_count; offset:3; size:1; signed:0; field:int common_pid; offset:4; size:4; signed:1; field:u64 lat; offset:8; size:8; signed:0; field:unsigned int order; offset:16; size:4; signed:0; field:gfp_t gfp_flags; offset:24; size:4; signed:1; field:int migratetype; offset:32; size:4; signed:1; print fmt: "lat=%llu, order=%u, gfp_flags=%x, migratetype=%d", REC->lat, REC->order, REC->gfp_flags, REC->migratetype Signed-off-by: Zhengjun Xing --- kernel/trace/trace_events_hist.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index 57648c5aa679..7482a1466ebf 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -679,6 +679,8 @@ static bool synth_field_signed(char *type) { if (str_has_prefix(type, "u")) return false; + if (strcmp(type, "gfp_t") == 0) + return false; return true; } -- 2.17.1
[PATCH] tracing: fix "gfp_t" format for synthetic events
In the format of synthetic events, the "gfp_t" is shown as "signed:1", but in fact the "gfp_t" is "unsigned", should be shown as "signed:0". The offset should be increased by the real size of each field, rather than by the size of "u64". The issue can be reproduced by the following commands: echo 'memlatency u64 lat; unsigned int order; gfp_t gfp_flags; int migratetype' > /sys/kernel/debug/tracing/synthetic_events cat /sys/kernel/debug/tracing/events/synthetic/memlatency/format name: memlatency ID: 2233 format: field:unsigned short common_type; offset:0; size:2; signed:0; field:unsigned char common_flags; offset:2; size:1; signed:0; field:unsigned char common_preempt_count; offset:3; size:1; signed:0; field:int common_pid; offset:4; size:4; signed:1; field:u64 lat; offset:8; size:8; signed:0; field:unsigned int order; offset:16; size:4; signed:0; field:gfp_t gfp_flags; offset:24; size:4; signed:1; field:int migratetype; offset:32; size:4; signed:1; print fmt: "lat=%llu, order=%u, gfp_flags=%x, migratetype=%d", REC->lat, REC->order, REC->gfp_flags, REC->migratetype Signed-off-by: Zhengjun Xing --- kernel/trace/trace_events_hist.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index 57648c5aa679..7d70321d03b1 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -665,7 +665,7 @@ static int synth_event_define_fields(struct trace_event_call *call) offset += STR_VAR_LEN_MAX; n_u64 += STR_VAR_LEN_MAX / sizeof(u64); } else { - offset += sizeof(u64); + offset += size; n_u64++; } } @@ -679,6 +679,8 @@ static bool synth_field_signed(char *type) { if (str_has_prefix(type, "u")) return false; + if (strcmp(type, "gfp_t") == 0) + return false; return true; } -- 2.17.1
[PATCH v3] trace:Add "gfp_t" support in synthetic_events
Add "gfp_t" support in synthetic_events, then the "gfp_t" type parameter in some functions can be traced. Prints the gfp flags as hex in addition to the human-readable flag string. Example output: whoopsie-630 [000] ...1 78.969452: testevent: bar=b20 (GFP_ATOMIC|__GFP_ZERO) rcuc/0-11 [000] ...1 81.097555: testevent: bar=a20 (GFP_ATOMIC) rcuc/0-11 [000] ...1 81.583123: testevent: bar=a20 (GFP_ATOMIC) Signed-off-by: Tom Zanussi Signed-off-by: Zhengjun Xing --- kernel/trace/trace_events_hist.c | 19 +++ 1 file changed, 19 insertions(+) diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index ca6b0dff60c5..30f0f32aca62 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -13,6 +13,10 @@ #include #include +/* for gfp flag names */ +#include +#include + #include "tracing_map.h" #include "trace.h" #include "trace_dynevent.h" @@ -752,6 +756,8 @@ static int synth_field_size(char *type) size = sizeof(unsigned long); else if (strcmp(type, "pid_t") == 0) size = sizeof(pid_t); + else if (strcmp(type, "gfp_t") == 0) + size = sizeof(gfp_t); else if (synth_field_is_string(type)) size = synth_field_string_size(type); @@ -792,6 +798,8 @@ static const char *synth_field_fmt(char *type) fmt = "%lu"; else if (strcmp(type, "pid_t") == 0) fmt = "%d"; + else if (strcmp(type, "gfp_t") == 0) + fmt = "%x"; else if (synth_field_is_string(type)) fmt = "%s"; @@ -834,9 +842,20 @@ static enum print_line_t print_synth_event(struct trace_iterator *iter, i == se->n_fields - 1 ? "" : " "); n_u64 += STR_VAR_LEN_MAX / sizeof(u64); } else { + struct trace_print_flags __flags[] = { + __def_gfpflag_names, {-1, NULL} }; + trace_seq_printf(s, print_fmt, se->fields[i]->name, entry->fields[n_u64], i == se->n_fields - 1 ? "" : " "); + + if (strcmp(se->fields[i]->type, "gfp_t") == 0) { + trace_seq_puts(s, " ("); + trace_print_flags_seq(s, "|", + entry->fields[n_u64], + __flags); + trace_seq_putc(s, ')'); + } n_u64++; } } -- 2.14.1
[PATCH v2] tracing: Add verbose gfp_flag printing to synthetic events
Add on top of 'trace:add "gfp_t" support in synthetic_events'. Prints the gfp flags as hex in addition to the human-readable flag string. Example output: whoopsie-630 [000] ...1 78.969452: testevent: bar=b20 (GFP_ATOMIC|__GFP_ZERO) rcuc/0-11 [000] ...1 81.097555: testevent: bar=a20 (GFP_ATOMIC) rcuc/0-11 [000] ...1 81.583123: testevent: bar=a20 (GFP_ATOMIC) Signed-off-by: Tom Zanussi Signed-off-by: Zhengjun Xing --- kernel/trace/trace_events_hist.c | 19 +++ 1 file changed, 19 insertions(+) diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index ca6b0dff60c5..938ef3f54c5c 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -13,6 +13,10 @@ #include #include +/* for gfp flag names */ +#include +#include + #include "tracing_map.h" #include "trace.h" #include "trace_dynevent.h" @@ -752,6 +756,8 @@ static int synth_field_size(char *type) size = sizeof(unsigned long); else if (strcmp(type, "pid_t") == 0) size = sizeof(pid_t); + else if (strcmp(type, "gfp_t") == 0) + size = sizeof(gfp_t); else if (synth_field_is_string(type)) size = synth_field_string_size(type); @@ -792,6 +798,8 @@ static const char *synth_field_fmt(char *type) fmt = "%lu"; else if (strcmp(type, "pid_t") == 0) fmt = "%d"; + else if (strcmp(type, "gfp_t") == 0) + fmt = "%x"; else if (synth_field_is_string(type)) fmt = "%s"; @@ -834,9 +838,20 @@ static enum print_line_t print_synth_event(struct trace_iterator *iter, i == se->n_fields - 1 ? "" : " "); n_u64 += STR_VAR_LEN_MAX / sizeof(u64); } else { + struct trace_print_flags __flags[] = { + __def_gfpflag_names, {-1, NULL} }; + trace_seq_printf(s, print_fmt, se->fields[i]->name, entry->fields[n_u64], i == se->n_fields - 1 ? "" : " "); + + if (strcmp(se->fields[i]->type, "gfp_t") == 0) { + trace_seq_puts(s, " ("); + trace_print_flags_seq(s, "|", + entry->fields[n_u64], + __flags); + trace_seq_putc(s, ')'); + } n_u64++; } } -- 2.14.1
[PATCH] trace:add "gfp_t" support in synthetic_events
Add "gfp_t" support in synthetic_events, then the "gfp_t" type parameter in some functions can be traced. Signed-off-by: Zhengjun Xing --- kernel/trace/trace_events_hist.c | 4 1 file changed, 4 insertions(+) diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index ca6b0dff60c5..0d3ab01b7cb5 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -752,6 +752,8 @@ static int synth_field_size(char *type) size = sizeof(unsigned long); else if (strcmp(type, "pid_t") == 0) size = sizeof(pid_t); + else if (strcmp(type, "gfp_t") == 0) + size = sizeof(gfp_t); else if (synth_field_is_string(type)) size = synth_field_string_size(type); @@ -792,6 +794,8 @@ static const char *synth_field_fmt(char *type) fmt = "%lu"; else if (strcmp(type, "pid_t") == 0) fmt = "%d"; + else if (strcmp(type, "gfp_t") == 0) + fmt = "%u"; else if (synth_field_is_string(type)) fmt = "%s"; -- 2.14.1
[PATCH] USB:fix USB3 devices behind USB3 hubs not resuming at hibernate thaw
USB3 hubs don't support global suspend. USB3 specification 10.10, Enhanced SuperSpeed hubs only support selective suspend and resume, they do not support global suspend/resume where the hub downstream facing ports states are not affected. When system enters hibernation it first enters freeze process where only the root hub enters suspend, usb_port_suspend() is not called for other devices, and suspend status flags are not set for them. Other devices are expected to suspend globally. Some external USB3 hubs will suspend the downstream facing port at global suspend. These devices won't be resumed at thaw as the suspend status flag is not set. A USB3 removable hard disk connected through a USB3 hub that won't resume at thaw will fail to synchronize SCSI cache, return “cmd cmplt err -71” error, and needs a 60 seconds timeout which causing system hang for 60s before the USB host reset the port for the USB3 removable hard disk to recover. Fix this by always calling usb_port_suspend() during freeze for USB3 devices. Signed-off-by: Zhengjun Xing <zhengjun.x...@linux.intel.com> --- drivers/usb/core/generic.c | 9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 83c14dda6300..bc8242bc4564 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -210,8 +210,13 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg) if (!udev->parent) rc = hcd_bus_suspend(udev, msg); - /* Non-root devices don't need to do anything for FREEZE or PRETHAW */ - else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) + /* +* Non-root USB2 devices don't need to do anything for FREEZE +* or PRETHAW. USB3 devices don't support global suspend and +* needs to be selectively suspended. +*/ + else if ((msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) +&& (udev->speed < USB_SPEED_SUPER)) rc = 0; else rc = usb_port_suspend(udev, msg); -- 2.11.0
[PATCH] USB:fix USB3 devices behind USB3 hubs not resuming at hibernate thaw
USB3 hubs don't support global suspend. USB3 specification 10.10, Enhanced SuperSpeed hubs only support selective suspend and resume, they do not support global suspend/resume where the hub downstream facing ports states are not affected. When system enters hibernation it first enters freeze process where only the root hub enters suspend, usb_port_suspend() is not called for other devices, and suspend status flags are not set for them. Other devices are expected to suspend globally. Some external USB3 hubs will suspend the downstream facing port at global suspend. These devices won't be resumed at thaw as the suspend status flag is not set. A USB3 removable hard disk connected through a USB3 hub that won't resume at thaw will fail to synchronize SCSI cache, return “cmd cmplt err -71” error, and needs a 60 seconds timeout which causing system hang for 60s before the USB host reset the port for the USB3 removable hard disk to recover. Fix this by always calling usb_port_suspend() during freeze for USB3 devices. Signed-off-by: Zhengjun Xing --- drivers/usb/core/generic.c | 9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 83c14dda6300..bc8242bc4564 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -210,8 +210,13 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg) if (!udev->parent) rc = hcd_bus_suspend(udev, msg); - /* Non-root devices don't need to do anything for FREEZE or PRETHAW */ - else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) + /* +* Non-root USB2 devices don't need to do anything for FREEZE +* or PRETHAW. USB3 devices don't support global suspend and +* needs to be selectively suspended. +*/ + else if ((msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) +&& (udev->speed < USB_SPEED_SUPER)) rc = 0; else rc = usb_port_suspend(udev, msg); -- 2.11.0
[PATCH] xhci:Fix NULL pointer in xhci debugfs
Commit dde634057da7 ("xhci: Fix use-after-free in xhci debugfs") causes a null pointer dereference while fixing xhci-debugfs usage of ring pointers that were freed during hibernate. The fix passed addresses to ring pointers instead, but forgot to do this change for the xhci_ring_trb_show function. The address of the ring pointer passed to xhci-debugfs was of a temporary ring pointer "new_ring" instead of the actual ring "ring" pointer. The temporary new_ring pointer will be set to NULL later causing the NULL pointer dereference. This issue was seen when reading xhci related files in debugfs: cat /sys/kernel/debug/usb/xhci/*/devices/*/ep*/trbs [ 184.604861] BUG: unable to handle kernel NULL pointer dereference at (null) [ 184.613776] IP: xhci_ring_trb_show+0x3a/0x890 [ 184.618733] PGD 264193067 P4D 264193067 PUD 263238067 PMD 0 [ 184.625184] Oops: [#1] SMP [ 184.726410] RIP: 0010:xhci_ring_trb_show+0x3a/0x890 [ 184.731944] RSP: 0018:ba8243c0fd90 EFLAGS: 00010246 [ 184.737880] RAX: RBX: RCX: 000295d6 [ 184.746020] RDX: 000295d5 RSI: 0001 RDI: 971a6418d400 [ 184.754121] RBP: R08: R09: [ 184.76] R10: 971a64c98a80 R11: 971a62a00e40 R12: 971a62a85500 [ 184.770325] R13: 0002 R14: 971a6418d400 R15: 971a6418d400 [ 184.778448] FS: 7fe725a79700() GS:971a6ec0() knlGS: [ 184.787644] CS: 0010 DS: ES: CR0: 80050033 [ 184.794168] CR2: CR3: 00025f365005 CR4: 003606f0 [ 184.802318] Call Trace: [ 184.805094] ? seq_read+0x281/0x3b0 [ 184.809068] seq_read+0xeb/0x3b0 [ 184.812735] full_proxy_read+0x4d/0x70 [ 184.817007] __vfs_read+0x23/0x120 [ 184.820870] vfs_read+0x91/0x130 [ 184.824538] SyS_read+0x42/0x90 [ 184.828106] entry_SYSCALL_64_fastpath+0x1a/0x7d Fixes: dde634057da7 ("xhci: Fix use-after-free in xhci debugfs") Signed-off-by: Zhengjun Xing <zhengjun.x...@linux.intel.com> --- drivers/usb/host/xhci-debugfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c index e26e685d8a57..5851052d4668 100644 --- a/drivers/usb/host/xhci-debugfs.c +++ b/drivers/usb/host/xhci-debugfs.c @@ -211,7 +211,7 @@ static void xhci_ring_dump_segment(struct seq_file *s, static int xhci_ring_trb_show(struct seq_file *s, void *unused) { int i; - struct xhci_ring*ring = s->private; + struct xhci_ring*ring = *(struct xhci_ring **)s->private; struct xhci_segment *seg = ring->first_seg; for (i = 0; i < ring->num_segs; i++) { @@ -387,7 +387,7 @@ void xhci_debugfs_create_endpoint(struct xhci_hcd *xhci, snprintf(epriv->name, sizeof(epriv->name), "ep%02d", ep_index); epriv->root = xhci_debugfs_create_ring_dir(xhci, - >eps[ep_index].new_ring, + >eps[ep_index].ring, epriv->name, spriv->root); spriv->eps[ep_index] = epriv; -- 2.11.0
[PATCH] xhci:Fix NULL pointer in xhci debugfs
Commit dde634057da7 ("xhci: Fix use-after-free in xhci debugfs") causes a null pointer dereference while fixing xhci-debugfs usage of ring pointers that were freed during hibernate. The fix passed addresses to ring pointers instead, but forgot to do this change for the xhci_ring_trb_show function. The address of the ring pointer passed to xhci-debugfs was of a temporary ring pointer "new_ring" instead of the actual ring "ring" pointer. The temporary new_ring pointer will be set to NULL later causing the NULL pointer dereference. This issue was seen when reading xhci related files in debugfs: cat /sys/kernel/debug/usb/xhci/*/devices/*/ep*/trbs [ 184.604861] BUG: unable to handle kernel NULL pointer dereference at (null) [ 184.613776] IP: xhci_ring_trb_show+0x3a/0x890 [ 184.618733] PGD 264193067 P4D 264193067 PUD 263238067 PMD 0 [ 184.625184] Oops: [#1] SMP [ 184.726410] RIP: 0010:xhci_ring_trb_show+0x3a/0x890 [ 184.731944] RSP: 0018:ba8243c0fd90 EFLAGS: 00010246 [ 184.737880] RAX: RBX: RCX: 000295d6 [ 184.746020] RDX: 000295d5 RSI: 0001 RDI: 971a6418d400 [ 184.754121] RBP: R08: R09: [ 184.76] R10: 971a64c98a80 R11: 971a62a00e40 R12: 971a62a85500 [ 184.770325] R13: 0002 R14: 971a6418d400 R15: 971a6418d400 [ 184.778448] FS: 7fe725a79700() GS:971a6ec0() knlGS: [ 184.787644] CS: 0010 DS: ES: CR0: 80050033 [ 184.794168] CR2: CR3: 00025f365005 CR4: 003606f0 [ 184.802318] Call Trace: [ 184.805094] ? seq_read+0x281/0x3b0 [ 184.809068] seq_read+0xeb/0x3b0 [ 184.812735] full_proxy_read+0x4d/0x70 [ 184.817007] __vfs_read+0x23/0x120 [ 184.820870] vfs_read+0x91/0x130 [ 184.824538] SyS_read+0x42/0x90 [ 184.828106] entry_SYSCALL_64_fastpath+0x1a/0x7d Fixes: dde634057da7 ("xhci: Fix use-after-free in xhci debugfs") Signed-off-by: Zhengjun Xing --- drivers/usb/host/xhci-debugfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c index e26e685d8a57..5851052d4668 100644 --- a/drivers/usb/host/xhci-debugfs.c +++ b/drivers/usb/host/xhci-debugfs.c @@ -211,7 +211,7 @@ static void xhci_ring_dump_segment(struct seq_file *s, static int xhci_ring_trb_show(struct seq_file *s, void *unused) { int i; - struct xhci_ring*ring = s->private; + struct xhci_ring*ring = *(struct xhci_ring **)s->private; struct xhci_segment *seg = ring->first_seg; for (i = 0; i < ring->num_segs; i++) { @@ -387,7 +387,7 @@ void xhci_debugfs_create_endpoint(struct xhci_hcd *xhci, snprintf(epriv->name, sizeof(epriv->name), "ep%02d", ep_index); epriv->root = xhci_debugfs_create_ring_dir(xhci, - >eps[ep_index].new_ring, + >eps[ep_index].ring, epriv->name, spriv->root); spriv->eps[ep_index] = epriv; -- 2.11.0
[PATCH] tracing: Add *iter check for NULL
From: xingzhen3debb0a9ddb adding a "__used" to the variable in the __trace_printk_fmt section. Sometimes it will cause *iter to be NULL, then strcmp in lookup_format and strcpy in hold_module_trace_bprintk_format will panic. Signed-off-by: xingzhen --- kernel/trace/trace_printk.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c index f96f038..82ecfb5 100644 --- a/kernel/trace/trace_printk.c +++ b/kernel/trace/trace_printk.c @@ -55,6 +55,8 @@ void hold_module_trace_bprintk_format(const char **start, const char **end) mutex_lock(_mutex); for (iter = start; iter < end; iter++) { + if (!*iter) + goto err; struct trace_bprintk_fmt *tb_fmt = lookup_format(*iter); if (tb_fmt) { *iter = tb_fmt->fmt; @@ -75,6 +77,7 @@ void hold_module_trace_bprintk_format(const char **start, const char **end) *iter = fmt; } +err: mutex_unlock(_mutex); } -- 1.9.1
[PATCH] tracing: Add *iter check for NULL
From: xingzhen 3debb0a9ddb adding a "__used" to the variable in the __trace_printk_fmt section. Sometimes it will cause *iter to be NULL, then strcmp in lookup_format and strcpy in hold_module_trace_bprintk_format will panic. Signed-off-by: xingzhen --- kernel/trace/trace_printk.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c index f96f038..82ecfb5 100644 --- a/kernel/trace/trace_printk.c +++ b/kernel/trace/trace_printk.c @@ -55,6 +55,8 @@ void hold_module_trace_bprintk_format(const char **start, const char **end) mutex_lock(_mutex); for (iter = start; iter < end; iter++) { + if (!*iter) + goto err; struct trace_bprintk_fmt *tb_fmt = lookup_format(*iter); if (tb_fmt) { *iter = tb_fmt->fmt; @@ -75,6 +77,7 @@ void hold_module_trace_bprintk_format(const char **start, const char **end) *iter = fmt; } +err: mutex_unlock(_mutex); } -- 1.9.1