summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2015-12-15 16:06:10 -0500
committerSteven Rostedt <rostedt@goodmis.org>2015-12-16 15:46:07 -0500
commita50bd43935586420fb75f4558369eb08566fac5e (patch)
tree63ad335cf267ffb4a9a4500498de4f1eb050e3b4 /scripts
parentdd39a26538e37f6c6131e829a4a510787e43c783 (diff)
ftrace/scripts: Have recordmcount copy the object file
Russell King found that he had weird side effects when compiling the kernel with hard linked ccache. The reason was that recordmcount modified the kernel in place via mmap, and when a file gets modified twice by recordmcount, it will complain about it. To fix this issue, Russell wrote a patch that checked if the file was hard linked more than once and would unlink it if it was. Linus Torvalds was not happy with the fact that recordmcount does this in place modification. Instead of doing the unlink only if the file has two or more hard links, it does the unlink all the time. In otherwords, it always does a copy if it changed something. That is, it does the write out if a change was made. Cc: stable@vger.kernel.org # 2.6.37+ Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'scripts')
-rw-r--r--scripts/recordmcount.c145
1 files changed, 110 insertions, 35 deletions
diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c
index 91705ef30402..301d70b0174f 100644
--- a/scripts/recordmcount.c
+++ b/scripts/recordmcount.c
@@ -48,12 +48,17 @@
48 48
49static int fd_map; /* File descriptor for file being modified. */ 49static int fd_map; /* File descriptor for file being modified. */
50static int mmap_failed; /* Boolean flag. */ 50static int mmap_failed; /* Boolean flag. */
51static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */
52static char gpfx; /* prefix for global symbol name (sometimes '_') */ 51static char gpfx; /* prefix for global symbol name (sometimes '_') */
53static struct stat sb; /* Remember .st_size, etc. */ 52static struct stat sb; /* Remember .st_size, etc. */
54static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */ 53static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */
55static const char *altmcount; /* alternate mcount symbol name */ 54static const char *altmcount; /* alternate mcount symbol name */
56static int warn_on_notrace_sect; /* warn when section has mcount not being recorded */ 55static int warn_on_notrace_sect; /* warn when section has mcount not being recorded */
56static void *file_map; /* pointer of the mapped file */
57static void *file_end; /* pointer to the end of the mapped file */
58static int file_updated; /* flag to state file was changed */
59static void *file_ptr; /* current file pointer location */
60static void *file_append; /* added to the end of the file */
61static size_t file_append_size; /* how much is added to end of file */
57 62
58/* setjmp() return values */ 63/* setjmp() return values */
59enum { 64enum {
@@ -67,10 +72,14 @@ static void
67cleanup(void) 72cleanup(void)
68{ 73{
69 if (!mmap_failed) 74 if (!mmap_failed)
70 munmap(ehdr_curr, sb.st_size); 75 munmap(file_map, sb.st_size);
71 else 76 else
72 free(ehdr_curr); 77 free(file_map);
73 close(fd_map); 78 file_map = NULL;
79 free(file_append);
80 file_append = NULL;
81 file_append_size = 0;
82 file_updated = 0;
74} 83}
75 84
76static void __attribute__((noreturn)) 85static void __attribute__((noreturn))
@@ -92,12 +101,22 @@ succeed_file(void)
92static off_t 101static off_t
93ulseek(int const fd, off_t const offset, int const whence) 102ulseek(int const fd, off_t const offset, int const whence)
94{ 103{
95 off_t const w = lseek(fd, offset, whence); 104 switch (whence) {
96 if (w == (off_t)-1) { 105 case SEEK_SET:
97 perror("lseek"); 106 file_ptr = file_map + offset;
107 break;
108 case SEEK_CUR:
109 file_ptr += offset;
110 break;
111 case SEEK_END:
112 file_ptr = file_map + (sb.st_size - offset);
113 break;
114 }
115 if (file_ptr < file_map) {
116 fprintf(stderr, "lseek: seek before file\n");
98 fail_file(); 117 fail_file();
99 } 118 }
100 return w; 119 return file_ptr - file_map;
101} 120}
102 121
103static size_t 122static size_t
@@ -114,12 +133,38 @@ uread(int const fd, void *const buf, size_t const count)
114static size_t 133static size_t
115uwrite(int const fd, void const *const buf, size_t const count) 134uwrite(int const fd, void const *const buf, size_t const count)
116{ 135{
117 size_t const n = write(fd, buf, count); 136 size_t cnt = count;
118 if (n != count) { 137 off_t idx = 0;
119 perror("write"); 138
120 fail_file(); 139 file_updated = 1;
140
141 if (file_ptr + count >= file_end) {
142 off_t aoffset = (file_ptr + count) - file_end;
143
144 if (aoffset > file_append_size) {
145 file_append = realloc(file_append, aoffset);
146 file_append_size = aoffset;
147 }
148 if (!file_append) {
149 perror("write");
150 fail_file();
151 }
152 if (file_ptr < file_end) {
153 cnt = file_end - file_ptr;
154 } else {
155 cnt = 0;
156 idx = aoffset - count;
157 }
121 } 158 }
122 return n; 159
160 if (cnt)
161 memcpy(file_ptr, buf, cnt);
162
163 if (cnt < count)
164 memcpy(file_append + idx, buf + cnt, count - cnt);
165
166 file_ptr += count;
167 return count;
123} 168}
124 169
125static void * 170static void *
@@ -192,9 +237,7 @@ static int make_nop_arm64(void *map, size_t const offset)
192 */ 237 */
193static void *mmap_file(char const *fname) 238static void *mmap_file(char const *fname)
194{ 239{
195 void *addr; 240 fd_map = open(fname, O_RDONLY);
196
197 fd_map = open(fname, O_RDWR);
198 if (fd_map < 0 || fstat(fd_map, &sb) < 0) { 241 if (fd_map < 0 || fstat(fd_map, &sb) < 0) {
199 perror(fname); 242 perror(fname);
200 fail_file(); 243 fail_file();
@@ -203,29 +246,58 @@ static void *mmap_file(char const *fname)
203 fprintf(stderr, "not a regular file: %s\n", fname); 246 fprintf(stderr, "not a regular file: %s\n", fname);
204 fail_file(); 247 fail_file();
205 } 248 }
206 addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, 249 file_map = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE,
207 fd_map, 0); 250 fd_map, 0);
208 mmap_failed = 0; 251 mmap_failed = 0;
209 if (addr == MAP_FAILED) { 252 if (file_map == MAP_FAILED) {
210 mmap_failed = 1; 253 mmap_failed = 1;
211 addr = umalloc(sb.st_size); 254 file_map = umalloc(sb.st_size);
212 uread(fd_map, addr, sb.st_size); 255 uread(fd_map, file_map, sb.st_size);
213 } 256 }
214 if (sb.st_nlink != 1) { 257 close(fd_map);
215 /* file is hard-linked, break the hard link */ 258
216 close(fd_map); 259 file_end = file_map + sb.st_size;
217 if (unlink(fname) < 0) { 260
218 perror(fname); 261 return file_map;
219 fail_file(); 262}
220 } 263
221 fd_map = open(fname, O_RDWR | O_CREAT, sb.st_mode); 264static void write_file(const char *fname)
222 if (fd_map < 0) { 265{
223 perror(fname); 266 char tmp_file[strlen(fname) + 4];
267 size_t n;
268
269 if (!file_updated)
270 return;
271
272 sprintf(tmp_file, "%s.rc", fname);
273
274 /*
275 * After reading the entire file into memory, delete it
276 * and write it back, to prevent weird side effects of modifying
277 * an object file in place.
278 */
279 fd_map = open(tmp_file, O_WRONLY | O_TRUNC | O_CREAT, sb.st_mode);
280 if (fd_map < 0) {
281 perror(fname);
282 fail_file();
283 }
284 n = write(fd_map, file_map, sb.st_size);
285 if (n != sb.st_size) {
286 perror("write");
287 fail_file();
288 }
289 if (file_append_size) {
290 n = write(fd_map, file_append, file_append_size);
291 if (n != file_append_size) {
292 perror("write");
224 fail_file(); 293 fail_file();
225 } 294 }
226 uwrite(fd_map, addr, sb.st_size);
227 } 295 }
228 return addr; 296 close(fd_map);
297 if (rename(tmp_file, fname) < 0) {
298 perror(fname);
299 fail_file();
300 }
229} 301}
230 302
231/* w8rev, w8nat, ...: Handle endianness. */ 303/* w8rev, w8nat, ...: Handle endianness. */
@@ -332,7 +404,6 @@ do_file(char const *const fname)
332 Elf32_Ehdr *const ehdr = mmap_file(fname); 404 Elf32_Ehdr *const ehdr = mmap_file(fname);
333 unsigned int reltype = 0; 405 unsigned int reltype = 0;
334 406
335 ehdr_curr = ehdr;
336 w = w4nat; 407 w = w4nat;
337 w2 = w2nat; 408 w2 = w2nat;
338 w8 = w8nat; 409 w8 = w8nat;
@@ -455,6 +526,7 @@ do_file(char const *const fname)
455 } 526 }
456 } /* end switch */ 527 } /* end switch */
457 528
529 write_file(fname);
458 cleanup(); 530 cleanup();
459} 531}
460 532
@@ -507,11 +579,14 @@ main(int argc, char *argv[])
507 case SJ_SETJMP: /* normal sequence */ 579 case SJ_SETJMP: /* normal sequence */
508 /* Avoid problems if early cleanup() */ 580 /* Avoid problems if early cleanup() */
509 fd_map = -1; 581 fd_map = -1;
510 ehdr_curr = NULL;
511 mmap_failed = 1; 582 mmap_failed = 1;
583 file_map = NULL;
584 file_ptr = NULL;
585 file_updated = 0;
512 do_file(file); 586 do_file(file);
513 break; 587 break;
514 case SJ_FAIL: /* error in do_file or below */ 588 case SJ_FAIL: /* error in do_file or below */
589 sprintf("%s: failed\n", file);
515 ++n_error; 590 ++n_error;
516 break; 591 break;
517 case SJ_SUCCEED: /* premature success */ 592 case SJ_SUCCEED: /* premature success */