mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 19:00:25 +00:00
Russell King was reporting lots of warnings when he compiled his kernel
with ftrace enabled. With some investigation it was discovered that it was his compile setup. He was using ccache with hard links, which allowed recordmcount to process the same .o twice. When this happens, recordmcount will detect that it was already done and give a warning about it. Russell fixed this by having recordmcount detect that the object file has more than one hard link, and if it does, it unlinks the object file after it maps it and processes then. This appears to fix the issue. As you did not like the fact that recordmcount modified the file in place and thought that it should do the modifications in memory and then write it out to disk and move it over the old file to prevent other more subtle issues like the one above, a second patch is added on top of Russell's to do just that. Luckily the original code had write and lseek wrappers that I was able to modify to not do inplace writes, but simply keep track of the changes made in memory. When a write is made, a "update" flag is set, and at the end of processing, if the update is set, then it writes the file with changes out to a new file, and then renames it over the original one. The file descriptor is still passed to the write and lseek wrappers because removing that would cause the change to be more intrusive. That can be removed in a follow up cleanup patch that can wait till the next merge window. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJWerqKAAoJEKKk/i67LK/80W0H/jbzBL4siTTenA0eZLmsxT8k nbAM4fpdylpqUc6ku3QwjqqvbYxaLhiQsDtsVgXEoV7eelDgBedOSvCCrpZXn5co y1VEunRfOIWMKLmoAdFUagWxdX25Pu9V6g74kdUwaiNnMtCy7+Ds7x8OwqASyd7t e1WAhQ63ovslN88hHpkQVxCApYaocyPgU1lysBpN9dmvUS7Vkt/Bl4xhlVclnQKS 3QbPWXtS/alCOOYj/Fa71Lfi2GhDx41Z6KPq6hFgph//oPHOSIvceNnimfT+ejjw 1dKzM5EN386PhF3R27P+I0ovXnLNlCKmMZQUCUvlU/CjOOHHcIQNj8WHw9XB20k= =5TS2 -----END PGP SIGNATURE----- Merge tag 'trace-v4.4-rc4-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace Pull ftrace/recordmcount fix from Steven Rostedt: "Russell King was reporting lots of warnings when he compiled his kernel with ftrace enabled. With some investigation it was discovered that it was his compile setup. He was using ccache with hard links, which allowed recordmcount to process the same .o twice. When this happens, recordmcount will detect that it was already done and give a warning about it. Russell fixed this by having recordmcount detect that the object file has more than one hard link, and if it does, it unlinks the object file after it maps it and processes then. This appears to fix the issue. As you did not like the fact that recordmcount modified the file in place and thought that it should do the modifications in memory and then write it out to disk and move it over the old file to prevent other more subtle issues like the one above, a second patch is added on top of Russell's to do just that. Luckily the original code had write and lseek wrappers that I was able to modify to not do inplace writes, but simply keep track of the changes made in memory. When a write is made, a "update" flag is set, and at the end of processing, if the update is set, then it writes the file with changes out to a new file, and then renames it over the original one. The file descriptor is still passed to the write and lseek wrappers because removing that would cause the change to be more intrusive. That can be removed in a follow up cleanup patch that can wait till the next merge window" * tag 'trace-v4.4-rc4-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: ftrace/scripts: Have recordmcount copy the object file scripts: recordmcount: break hardlinks
This commit is contained in:
commit
e2b0a16132
1 changed files with 113 additions and 24 deletions
|
@ -48,12 +48,17 @@
|
|||
|
||||
static int fd_map; /* File descriptor for file being modified. */
|
||||
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 struct stat sb; /* Remember .st_size, etc. */
|
||||
static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */
|
||||
static const char *altmcount; /* alternate mcount symbol name */
|
||||
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 */
|
||||
enum {
|
||||
|
@ -67,10 +72,14 @@ static void
|
|||
cleanup(void)
|
||||
{
|
||||
if (!mmap_failed)
|
||||
munmap(ehdr_curr, sb.st_size);
|
||||
munmap(file_map, sb.st_size);
|
||||
else
|
||||
free(ehdr_curr);
|
||||
close(fd_map);
|
||||
free(file_map);
|
||||
file_map = NULL;
|
||||
free(file_append);
|
||||
file_append = NULL;
|
||||
file_append_size = 0;
|
||||
file_updated = 0;
|
||||
}
|
||||
|
||||
static void __attribute__((noreturn))
|
||||
|
@ -92,12 +101,22 @@ succeed_file(void)
|
|||
static off_t
|
||||
ulseek(int const fd, off_t const offset, int const whence)
|
||||
{
|
||||
off_t const w = lseek(fd, offset, whence);
|
||||
if (w == (off_t)-1) {
|
||||
perror("lseek");
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
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();
|
||||
}
|
||||
return w;
|
||||
return file_ptr - file_map;
|
||||
}
|
||||
|
||||
static size_t
|
||||
|
@ -114,12 +133,38 @@ uread(int const fd, void *const buf, size_t const count)
|
|||
static size_t
|
||||
uwrite(int const fd, void const *const buf, size_t const count)
|
||||
{
|
||||
size_t const n = write(fd, buf, count);
|
||||
if (n != count) {
|
||||
perror("write");
|
||||
fail_file();
|
||||
size_t cnt = 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");
|
||||
fail_file();
|
||||
}
|
||||
if (file_ptr < file_end) {
|
||||
cnt = file_end - file_ptr;
|
||||
} else {
|
||||
cnt = 0;
|
||||
idx = aoffset - count;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
|
||||
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 *
|
||||
|
@ -192,9 +237,7 @@ static int make_nop_arm64(void *map, size_t const offset)
|
|||
*/
|
||||
static void *mmap_file(char const *fname)
|
||||
{
|
||||
void *addr;
|
||||
|
||||
fd_map = open(fname, O_RDWR);
|
||||
fd_map = open(fname, O_RDONLY);
|
||||
if (fd_map < 0 || fstat(fd_map, &sb) < 0) {
|
||||
perror(fname);
|
||||
fail_file();
|
||||
|
@ -203,15 +246,58 @@ static void *mmap_file(char const *fname)
|
|||
fprintf(stderr, "not a regular file: %s\n", fname);
|
||||
fail_file();
|
||||
}
|
||||
addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE,
|
||||
fd_map, 0);
|
||||
file_map = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE,
|
||||
fd_map, 0);
|
||||
mmap_failed = 0;
|
||||
if (addr == MAP_FAILED) {
|
||||
if (file_map == MAP_FAILED) {
|
||||
mmap_failed = 1;
|
||||
addr = umalloc(sb.st_size);
|
||||
uread(fd_map, addr, sb.st_size);
|
||||
file_map = umalloc(sb.st_size);
|
||||
uread(fd_map, file_map, sb.st_size);
|
||||
}
|
||||
close(fd_map);
|
||||
|
||||
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);
|
||||
fail_file();
|
||||
}
|
||||
n = write(fd_map, file_map, sb.st_size);
|
||||
if (n != sb.st_size) {
|
||||
perror("write");
|
||||
fail_file();
|
||||
}
|
||||
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. */
|
||||
|
@ -318,7 +404,6 @@ do_file(char const *const fname)
|
|||
Elf32_Ehdr *const ehdr = mmap_file(fname);
|
||||
unsigned int reltype = 0;
|
||||
|
||||
ehdr_curr = ehdr;
|
||||
w = w4nat;
|
||||
w2 = w2nat;
|
||||
w8 = w8nat;
|
||||
|
@ -441,6 +526,7 @@ do_file(char const *const fname)
|
|||
}
|
||||
} /* end switch */
|
||||
|
||||
write_file(fname);
|
||||
cleanup();
|
||||
}
|
||||
|
||||
|
@ -493,11 +579,14 @@ main(int argc, char *argv[])
|
|||
case SJ_SETJMP: /* normal sequence */
|
||||
/* Avoid problems if early cleanup() */
|
||||
fd_map = -1;
|
||||
ehdr_curr = NULL;
|
||||
mmap_failed = 1;
|
||||
file_map = NULL;
|
||||
file_ptr = NULL;
|
||||
file_updated = 0;
|
||||
do_file(file);
|
||||
break;
|
||||
case SJ_FAIL: /* error in do_file or below */
|
||||
sprintf("%s: failed\n", file);
|
||||
++n_error;
|
||||
break;
|
||||
case SJ_SUCCEED: /* premature success */
|
||||
|
|
Loading…
Reference in a new issue