diff options
author | Sage Weil <sage@inktank.com> | 2013-08-15 14:11:45 -0400 |
---|---|---|
committer | Sage Weil <sage@inktank.com> | 2013-08-15 14:11:45 -0400 |
commit | ee3e542fec6e69bc9fb668698889a37d93950ddf (patch) | |
tree | e74ee766a4764769ef1d3d45d266b4dea64101d3 /fs/coredump.c | |
parent | fe2a801b50c0bb8039d627e5ae1fec249d10ff39 (diff) | |
parent | f1d6e17f540af37bb1891480143669ba7636c4cf (diff) |
Merge remote-tracking branch 'linus/master' into testing
Diffstat (limited to 'fs/coredump.c')
-rw-r--r-- | fs/coredump.c | 121 |
1 files changed, 59 insertions, 62 deletions
diff --git a/fs/coredump.c b/fs/coredump.c index dafafbafa731..72f816d6cad9 100644 --- a/fs/coredump.c +++ b/fs/coredump.c | |||
@@ -45,69 +45,79 @@ | |||
45 | #include <trace/events/sched.h> | 45 | #include <trace/events/sched.h> |
46 | 46 | ||
47 | int core_uses_pid; | 47 | int core_uses_pid; |
48 | char core_pattern[CORENAME_MAX_SIZE] = "core"; | ||
49 | unsigned int core_pipe_limit; | 48 | unsigned int core_pipe_limit; |
49 | char core_pattern[CORENAME_MAX_SIZE] = "core"; | ||
50 | static int core_name_size = CORENAME_MAX_SIZE; | ||
50 | 51 | ||
51 | struct core_name { | 52 | struct core_name { |
52 | char *corename; | 53 | char *corename; |
53 | int used, size; | 54 | int used, size; |
54 | }; | 55 | }; |
55 | static atomic_t call_count = ATOMIC_INIT(1); | ||
56 | 56 | ||
57 | /* The maximal length of core_pattern is also specified in sysctl.c */ | 57 | /* The maximal length of core_pattern is also specified in sysctl.c */ |
58 | 58 | ||
59 | static int expand_corename(struct core_name *cn) | 59 | static int expand_corename(struct core_name *cn, int size) |
60 | { | 60 | { |
61 | char *old_corename = cn->corename; | 61 | char *corename = krealloc(cn->corename, size, GFP_KERNEL); |
62 | |||
63 | cn->size = CORENAME_MAX_SIZE * atomic_inc_return(&call_count); | ||
64 | cn->corename = krealloc(old_corename, cn->size, GFP_KERNEL); | ||
65 | 62 | ||
66 | if (!cn->corename) { | 63 | if (!corename) |
67 | kfree(old_corename); | ||
68 | return -ENOMEM; | 64 | return -ENOMEM; |
69 | } | ||
70 | 65 | ||
66 | if (size > core_name_size) /* racy but harmless */ | ||
67 | core_name_size = size; | ||
68 | |||
69 | cn->size = ksize(corename); | ||
70 | cn->corename = corename; | ||
71 | return 0; | 71 | return 0; |
72 | } | 72 | } |
73 | 73 | ||
74 | static int cn_vprintf(struct core_name *cn, const char *fmt, va_list arg) | ||
75 | { | ||
76 | int free, need; | ||
77 | |||
78 | again: | ||
79 | free = cn->size - cn->used; | ||
80 | need = vsnprintf(cn->corename + cn->used, free, fmt, arg); | ||
81 | if (need < free) { | ||
82 | cn->used += need; | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | if (!expand_corename(cn, cn->size + need - free + 1)) | ||
87 | goto again; | ||
88 | |||
89 | return -ENOMEM; | ||
90 | } | ||
91 | |||
74 | static int cn_printf(struct core_name *cn, const char *fmt, ...) | 92 | static int cn_printf(struct core_name *cn, const char *fmt, ...) |
75 | { | 93 | { |
76 | char *cur; | ||
77 | int need; | ||
78 | int ret; | ||
79 | va_list arg; | 94 | va_list arg; |
95 | int ret; | ||
80 | 96 | ||
81 | va_start(arg, fmt); | 97 | va_start(arg, fmt); |
82 | need = vsnprintf(NULL, 0, fmt, arg); | 98 | ret = cn_vprintf(cn, fmt, arg); |
83 | va_end(arg); | 99 | va_end(arg); |
84 | 100 | ||
85 | if (likely(need < cn->size - cn->used - 1)) | 101 | return ret; |
86 | goto out_printf; | 102 | } |
87 | 103 | ||
88 | ret = expand_corename(cn); | 104 | static int cn_esc_printf(struct core_name *cn, const char *fmt, ...) |
89 | if (ret) | 105 | { |
90 | goto expand_fail; | 106 | int cur = cn->used; |
107 | va_list arg; | ||
108 | int ret; | ||
91 | 109 | ||
92 | out_printf: | ||
93 | cur = cn->corename + cn->used; | ||
94 | va_start(arg, fmt); | 110 | va_start(arg, fmt); |
95 | vsnprintf(cur, need + 1, fmt, arg); | 111 | ret = cn_vprintf(cn, fmt, arg); |
96 | va_end(arg); | 112 | va_end(arg); |
97 | cn->used += need; | ||
98 | return 0; | ||
99 | 113 | ||
100 | expand_fail: | 114 | for (; cur < cn->used; ++cur) { |
115 | if (cn->corename[cur] == '/') | ||
116 | cn->corename[cur] = '!'; | ||
117 | } | ||
101 | return ret; | 118 | return ret; |
102 | } | 119 | } |
103 | 120 | ||
104 | static void cn_escape(char *str) | ||
105 | { | ||
106 | for (; *str; str++) | ||
107 | if (*str == '/') | ||
108 | *str = '!'; | ||
109 | } | ||
110 | |||
111 | static int cn_print_exe_file(struct core_name *cn) | 121 | static int cn_print_exe_file(struct core_name *cn) |
112 | { | 122 | { |
113 | struct file *exe_file; | 123 | struct file *exe_file; |
@@ -115,12 +125,8 @@ static int cn_print_exe_file(struct core_name *cn) | |||
115 | int ret; | 125 | int ret; |
116 | 126 | ||
117 | exe_file = get_mm_exe_file(current->mm); | 127 | exe_file = get_mm_exe_file(current->mm); |
118 | if (!exe_file) { | 128 | if (!exe_file) |
119 | char *commstart = cn->corename + cn->used; | 129 | return cn_esc_printf(cn, "%s (path unknown)", current->comm); |
120 | ret = cn_printf(cn, "%s (path unknown)", current->comm); | ||
121 | cn_escape(commstart); | ||
122 | return ret; | ||
123 | } | ||
124 | 130 | ||
125 | pathbuf = kmalloc(PATH_MAX, GFP_TEMPORARY); | 131 | pathbuf = kmalloc(PATH_MAX, GFP_TEMPORARY); |
126 | if (!pathbuf) { | 132 | if (!pathbuf) { |
@@ -134,9 +140,7 @@ static int cn_print_exe_file(struct core_name *cn) | |||
134 | goto free_buf; | 140 | goto free_buf; |
135 | } | 141 | } |
136 | 142 | ||
137 | cn_escape(path); | 143 | ret = cn_esc_printf(cn, "%s", path); |
138 | |||
139 | ret = cn_printf(cn, "%s", path); | ||
140 | 144 | ||
141 | free_buf: | 145 | free_buf: |
142 | kfree(pathbuf); | 146 | kfree(pathbuf); |
@@ -157,19 +161,19 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm) | |||
157 | int pid_in_pattern = 0; | 161 | int pid_in_pattern = 0; |
158 | int err = 0; | 162 | int err = 0; |
159 | 163 | ||
160 | cn->size = CORENAME_MAX_SIZE * atomic_read(&call_count); | ||
161 | cn->corename = kmalloc(cn->size, GFP_KERNEL); | ||
162 | cn->used = 0; | 164 | cn->used = 0; |
163 | 165 | cn->corename = NULL; | |
164 | if (!cn->corename) | 166 | if (expand_corename(cn, core_name_size)) |
165 | return -ENOMEM; | 167 | return -ENOMEM; |
168 | cn->corename[0] = '\0'; | ||
169 | |||
170 | if (ispipe) | ||
171 | ++pat_ptr; | ||
166 | 172 | ||
167 | /* Repeat as long as we have more pattern to process and more output | 173 | /* Repeat as long as we have more pattern to process and more output |
168 | space */ | 174 | space */ |
169 | while (*pat_ptr) { | 175 | while (*pat_ptr) { |
170 | if (*pat_ptr != '%') { | 176 | if (*pat_ptr != '%') { |
171 | if (*pat_ptr == 0) | ||
172 | goto out; | ||
173 | err = cn_printf(cn, "%c", *pat_ptr++); | 177 | err = cn_printf(cn, "%c", *pat_ptr++); |
174 | } else { | 178 | } else { |
175 | switch (*++pat_ptr) { | 179 | switch (*++pat_ptr) { |
@@ -210,22 +214,16 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm) | |||
210 | break; | 214 | break; |
211 | } | 215 | } |
212 | /* hostname */ | 216 | /* hostname */ |
213 | case 'h': { | 217 | case 'h': |
214 | char *namestart = cn->corename + cn->used; | ||
215 | down_read(&uts_sem); | 218 | down_read(&uts_sem); |
216 | err = cn_printf(cn, "%s", | 219 | err = cn_esc_printf(cn, "%s", |
217 | utsname()->nodename); | 220 | utsname()->nodename); |
218 | up_read(&uts_sem); | 221 | up_read(&uts_sem); |
219 | cn_escape(namestart); | ||
220 | break; | 222 | break; |
221 | } | ||
222 | /* executable */ | 223 | /* executable */ |
223 | case 'e': { | 224 | case 'e': |
224 | char *commstart = cn->corename + cn->used; | 225 | err = cn_esc_printf(cn, "%s", current->comm); |
225 | err = cn_printf(cn, "%s", current->comm); | ||
226 | cn_escape(commstart); | ||
227 | break; | 226 | break; |
228 | } | ||
229 | case 'E': | 227 | case 'E': |
230 | err = cn_print_exe_file(cn); | 228 | err = cn_print_exe_file(cn); |
231 | break; | 229 | break; |
@@ -244,6 +242,7 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm) | |||
244 | return err; | 242 | return err; |
245 | } | 243 | } |
246 | 244 | ||
245 | out: | ||
247 | /* Backward compatibility with core_uses_pid: | 246 | /* Backward compatibility with core_uses_pid: |
248 | * | 247 | * |
249 | * If core_pattern does not include a %p (as is the default) | 248 | * If core_pattern does not include a %p (as is the default) |
@@ -254,7 +253,6 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm) | |||
254 | if (err) | 253 | if (err) |
255 | return err; | 254 | return err; |
256 | } | 255 | } |
257 | out: | ||
258 | return ispipe; | 256 | return ispipe; |
259 | } | 257 | } |
260 | 258 | ||
@@ -549,7 +547,7 @@ void do_coredump(siginfo_t *siginfo) | |||
549 | if (ispipe < 0) { | 547 | if (ispipe < 0) { |
550 | printk(KERN_WARNING "format_corename failed\n"); | 548 | printk(KERN_WARNING "format_corename failed\n"); |
551 | printk(KERN_WARNING "Aborting core\n"); | 549 | printk(KERN_WARNING "Aborting core\n"); |
552 | goto fail_corename; | 550 | goto fail_unlock; |
553 | } | 551 | } |
554 | 552 | ||
555 | if (cprm.limit == 1) { | 553 | if (cprm.limit == 1) { |
@@ -584,7 +582,7 @@ void do_coredump(siginfo_t *siginfo) | |||
584 | goto fail_dropcount; | 582 | goto fail_dropcount; |
585 | } | 583 | } |
586 | 584 | ||
587 | helper_argv = argv_split(GFP_KERNEL, cn.corename+1, NULL); | 585 | helper_argv = argv_split(GFP_KERNEL, cn.corename, NULL); |
588 | if (!helper_argv) { | 586 | if (!helper_argv) { |
589 | printk(KERN_WARNING "%s failed to allocate memory\n", | 587 | printk(KERN_WARNING "%s failed to allocate memory\n", |
590 | __func__); | 588 | __func__); |
@@ -601,7 +599,7 @@ void do_coredump(siginfo_t *siginfo) | |||
601 | 599 | ||
602 | argv_free(helper_argv); | 600 | argv_free(helper_argv); |
603 | if (retval) { | 601 | if (retval) { |
604 | printk(KERN_INFO "Core dump to %s pipe failed\n", | 602 | printk(KERN_INFO "Core dump to |%s pipe failed\n", |
605 | cn.corename); | 603 | cn.corename); |
606 | goto close_fail; | 604 | goto close_fail; |
607 | } | 605 | } |
@@ -669,7 +667,6 @@ fail_dropcount: | |||
669 | atomic_dec(&core_dump_count); | 667 | atomic_dec(&core_dump_count); |
670 | fail_unlock: | 668 | fail_unlock: |
671 | kfree(cn.corename); | 669 | kfree(cn.corename); |
672 | fail_corename: | ||
673 | coredump_finish(mm, core_dumped); | 670 | coredump_finish(mm, core_dumped); |
674 | revert_creds(old_cred); | 671 | revert_creds(old_cred); |
675 | fail_creds: | 672 | fail_creds: |