提交 a50bd439 编写于 作者: S Steven Rostedt (Red Hat) 提交者: Steven Rostedt

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: NSteven Rostedt <rostedt@goodmis.org>
上级 dd39a265
...@@ -48,12 +48,17 @@ ...@@ -48,12 +48,17 @@
static int fd_map; /* File descriptor for file being modified. */ static int fd_map; /* File descriptor for file being modified. */
static int mmap_failed; /* Boolean flag. */ static int mmap_failed; /* Boolean flag. */
static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */
static char gpfx; /* prefix for global symbol name (sometimes '_') */ static char gpfx; /* prefix for global symbol name (sometimes '_') */
static struct stat sb; /* Remember .st_size, etc. */ static struct stat sb; /* Remember .st_size, etc. */
static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */ static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */
static const char *altmcount; /* alternate mcount symbol name */ static const char *altmcount; /* alternate mcount symbol name */
static int warn_on_notrace_sect; /* warn when section has mcount not being recorded */ static int warn_on_notrace_sect; /* warn when section has mcount not being recorded */
static void *file_map; /* pointer of the mapped file */
static void *file_end; /* pointer to the end of the mapped file */
static int file_updated; /* flag to state file was changed */
static void *file_ptr; /* current file pointer location */
static void *file_append; /* added to the end of the file */
static size_t file_append_size; /* how much is added to end of file */
/* setjmp() return values */ /* setjmp() return values */
enum { enum {
...@@ -67,10 +72,14 @@ static void ...@@ -67,10 +72,14 @@ static void
cleanup(void) cleanup(void)
{ {
if (!mmap_failed) if (!mmap_failed)
munmap(ehdr_curr, sb.st_size); munmap(file_map, sb.st_size);
else else
free(ehdr_curr); free(file_map);
close(fd_map); file_map = NULL;
free(file_append);
file_append = NULL;
file_append_size = 0;
file_updated = 0;
} }
static void __attribute__((noreturn)) static void __attribute__((noreturn))
...@@ -92,12 +101,22 @@ succeed_file(void) ...@@ -92,12 +101,22 @@ succeed_file(void)
static off_t static off_t
ulseek(int const fd, off_t const offset, int const whence) ulseek(int const fd, off_t const offset, int const whence)
{ {
off_t const w = lseek(fd, offset, whence); switch (whence) {
if (w == (off_t)-1) { case SEEK_SET:
perror("lseek"); file_ptr = file_map + offset;
break;
case SEEK_CUR:
file_ptr += offset;
break;
case SEEK_END:
file_ptr = file_map + (sb.st_size - offset);
break;
}
if (file_ptr < file_map) {
fprintf(stderr, "lseek: seek before file\n");
fail_file(); fail_file();
} }
return w; return file_ptr - file_map;
} }
static size_t static size_t
...@@ -114,12 +133,38 @@ uread(int const fd, void *const buf, size_t const count) ...@@ -114,12 +133,38 @@ uread(int const fd, void *const buf, size_t const count)
static size_t static size_t
uwrite(int const fd, void const *const buf, size_t const count) uwrite(int const fd, void const *const buf, size_t const count)
{ {
size_t const n = write(fd, buf, count); size_t cnt = count;
if (n != count) { off_t idx = 0;
file_updated = 1;
if (file_ptr + count >= file_end) {
off_t aoffset = (file_ptr + count) - file_end;
if (aoffset > file_append_size) {
file_append = realloc(file_append, aoffset);
file_append_size = aoffset;
}
if (!file_append) {
perror("write"); perror("write");
fail_file(); fail_file();
} }
return n; if (file_ptr < file_end) {
cnt = file_end - file_ptr;
} else {
cnt = 0;
idx = aoffset - count;
}
}
if (cnt)
memcpy(file_ptr, buf, cnt);
if (cnt < count)
memcpy(file_append + idx, buf + cnt, count - cnt);
file_ptr += count;
return count;
} }
static void * static void *
...@@ -192,9 +237,7 @@ static int make_nop_arm64(void *map, size_t const offset) ...@@ -192,9 +237,7 @@ static int make_nop_arm64(void *map, size_t const offset)
*/ */
static void *mmap_file(char const *fname) static void *mmap_file(char const *fname)
{ {
void *addr; fd_map = open(fname, O_RDONLY);
fd_map = open(fname, O_RDWR);
if (fd_map < 0 || fstat(fd_map, &sb) < 0) { if (fd_map < 0 || fstat(fd_map, &sb) < 0) {
perror(fname); perror(fname);
fail_file(); fail_file();
...@@ -203,29 +246,58 @@ static void *mmap_file(char const *fname) ...@@ -203,29 +246,58 @@ static void *mmap_file(char const *fname)
fprintf(stderr, "not a regular file: %s\n", fname); fprintf(stderr, "not a regular file: %s\n", fname);
fail_file(); fail_file();
} }
addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, file_map = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE,
fd_map, 0); fd_map, 0);
mmap_failed = 0; mmap_failed = 0;
if (addr == MAP_FAILED) { if (file_map == MAP_FAILED) {
mmap_failed = 1; mmap_failed = 1;
addr = umalloc(sb.st_size); file_map = umalloc(sb.st_size);
uread(fd_map, addr, sb.st_size); uread(fd_map, file_map, sb.st_size);
} }
if (sb.st_nlink != 1) {
/* file is hard-linked, break the hard link */
close(fd_map); close(fd_map);
if (unlink(fname) < 0) {
file_end = file_map + sb.st_size;
return file_map;
}
static void write_file(const char *fname)
{
char tmp_file[strlen(fname) + 4];
size_t n;
if (!file_updated)
return;
sprintf(tmp_file, "%s.rc", fname);
/*
* After reading the entire file into memory, delete it
* and write it back, to prevent weird side effects of modifying
* an object file in place.
*/
fd_map = open(tmp_file, O_WRONLY | O_TRUNC | O_CREAT, sb.st_mode);
if (fd_map < 0) {
perror(fname); perror(fname);
fail_file(); fail_file();
} }
fd_map = open(fname, O_RDWR | O_CREAT, sb.st_mode); n = write(fd_map, file_map, sb.st_size);
if (fd_map < 0) { if (n != sb.st_size) {
perror(fname); perror("write");
fail_file(); fail_file();
} }
uwrite(fd_map, addr, sb.st_size); if (file_append_size) {
n = write(fd_map, file_append, file_append_size);
if (n != file_append_size) {
perror("write");
fail_file();
}
}
close(fd_map);
if (rename(tmp_file, fname) < 0) {
perror(fname);
fail_file();
} }
return addr;
} }
/* w8rev, w8nat, ...: Handle endianness. */ /* w8rev, w8nat, ...: Handle endianness. */
...@@ -332,7 +404,6 @@ do_file(char const *const fname) ...@@ -332,7 +404,6 @@ do_file(char const *const fname)
Elf32_Ehdr *const ehdr = mmap_file(fname); Elf32_Ehdr *const ehdr = mmap_file(fname);
unsigned int reltype = 0; unsigned int reltype = 0;
ehdr_curr = ehdr;
w = w4nat; w = w4nat;
w2 = w2nat; w2 = w2nat;
w8 = w8nat; w8 = w8nat;
...@@ -455,6 +526,7 @@ do_file(char const *const fname) ...@@ -455,6 +526,7 @@ do_file(char const *const fname)
} }
} /* end switch */ } /* end switch */
write_file(fname);
cleanup(); cleanup();
} }
...@@ -507,11 +579,14 @@ main(int argc, char *argv[]) ...@@ -507,11 +579,14 @@ main(int argc, char *argv[])
case SJ_SETJMP: /* normal sequence */ case SJ_SETJMP: /* normal sequence */
/* Avoid problems if early cleanup() */ /* Avoid problems if early cleanup() */
fd_map = -1; fd_map = -1;
ehdr_curr = NULL;
mmap_failed = 1; mmap_failed = 1;
file_map = NULL;
file_ptr = NULL;
file_updated = 0;
do_file(file); do_file(file);
break; break;
case SJ_FAIL: /* error in do_file or below */ case SJ_FAIL: /* error in do_file or below */
sprintf("%s: failed\n", file);
++n_error; ++n_error;
break; break;
case SJ_SUCCEED: /* premature success */ case SJ_SUCCEED: /* premature success */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册