From 74b7c9d452c97a948852416e1456a3117deec2dc Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Sun, 4 Nov 2012 18:51:20 -0800 Subject: prepstrip: account for new inode created by strip Since strip creates a new inode, we need to know the initial set of inodes in advance, so that we can avoid interference due to trying to strip the same (hardlinked) file multiple times in parallel. See bug #421099. --- bin/ebuild-helpers/prepstrip | 60 +++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/bin/ebuild-helpers/prepstrip b/bin/ebuild-helpers/prepstrip index 0d1ce5a09..c6bf60e1d 100755 --- a/bin/ebuild-helpers/prepstrip +++ b/bin/ebuild-helpers/prepstrip @@ -94,7 +94,6 @@ save_elf_sources() { fi local x=$1 - [[ -f $(inode_file_link "${x}") ]] && return 0 # since we're editing the ELF here, we should recompute the build-id # (the -i flag below). save that output so we don't need to recompute @@ -115,7 +114,8 @@ save_elf_debug() { # twice in this path) in order for gdb's debug-file-directory # lookup to work correctly. local x=$1 - local splitdebug=$2 + local inode_debug=$2 + local splitdebug=$3 local y=${ED}usr/lib/debug/${x:${#D}}.debug # dont save debug info twice @@ -123,9 +123,8 @@ save_elf_debug() { mkdir -p "${y%/*}" - local inode=$(inode_file_link "${x}") - if [[ -f ${inode} ]] ; then - ln "${inode}" "${y}" + if [ -f "${inode_debug}" ] ; then + ln "${inode_debug}" "${y}" || die "ln failed unexpectedly" else if [[ -n ${splitdebug} ]] ; then mv "${splitdebug}" "${y}" @@ -138,7 +137,7 @@ save_elf_debug() { local args="a-x,o-w" [[ -g ${x} || -u ${x} ]] && args+=",go-r" chmod ${args} "${y}" - ln "${y}" "${inode}" + ln "${y}" "${inode_debug}" || die "ln failed unexpectedly" fi # if we don't already have build-id from debugedit, look it up @@ -158,7 +157,8 @@ save_elf_debug() { # Usage: process_elf process_elf() { - local x=$1 strip_flags=${*:2} + local x=$1 inode_link=$2 strip_flags=${*:3} + local already_stripped lockfile __vecho " ${x:${#ED}}" @@ -167,15 +167,17 @@ process_elf() { # So, use a lockfile to prevent interference (easily observed with # dev-vcs/git which creates ~111 hardlinks to one file in # /usr/libexec/git-core). - local lockfile=$(inode_file_link "${x}")_lockfile - if ! ln "${x}" "${lockfile}" 2>/dev/null ; then + lockfile=${inode_link}_lockfile + if ! ln "${inode_link}" "${lockfile}" 2>/dev/null ; then while [[ -f ${lockfile} ]] ; do sleep 1 done unset lockfile fi - save_elf_sources "${x}" + [ -f "${inode_link}_stripped" ] && already_stripped=true || already_stripped=false + + ${already_stripped} || save_elf_sources "${x}" if ${strip_this} ; then @@ -183,17 +185,26 @@ process_elf() { if [[ -n ${SPLIT_STRIP_FLAGS} ]] ; then local shortname="${x##*/}.debug" local splitdebug="${tmpdir}/splitdebug/${shortname}.${BASHPID}" + ${already_stripped} || \ ${STRIP} ${strip_flags} \ -f "${splitdebug}" \ -F "${shortname}" \ "${x}" - save_elf_debug "${x}" "${splitdebug}" + save_elf_debug "${x}" "${inode_link}_debug" "${splitdebug}" else - save_elf_debug "${x}" + save_elf_debug "${x}" "${inode_link}_debug" + ${already_stripped} || \ ${STRIP} ${strip_flags} "${x}" fi fi + if ${already_stripped} ; then + rm -f "${x}" || die "rm failed unexpectedly" + ln "${inode_link}_stripped" "${x}" || die "ln failed unexpectedly" + else + ln "${x}" "${inode_link}_stripped" || die "ln failed unexpectedly" + fi + [[ -n ${lockfile} ]] && rm -f "${lockfile}" } @@ -232,11 +243,24 @@ if ! ${RESTRICT_binchecks} && ! ${RESTRICT_strip} ; then __multijob_post_fork fi +# Since strip creates a new inode, we need to know the initial set of +# inodes in advance, so that we can avoid interference due to trying +# to strip the same (hardlinked) file multiple times in parallel. +# See bug #421099. +while read -r x ; do + inode_link=$(inode_file_link "${x}") + echo "${x}" >> "${inode_link}" || die "echo failed" +done < <( + scanelf -yqRBF '#k%F' -k '.symtab' "$@" + find "$@" -type f ! -type l -name '*.a' +) + # Now we look for unstripped binaries. -for x in \ - $(scanelf -yqRBF '#k%F' -k '.symtab' "$@") \ - $(find "$@" -type f -name '*.a') +cd "${tmpdir}/inodes" || die "cd failed" +for inode_link in * ; do +while read -r x do + if ! ${banner} ; then __vecho "strip: ${STRIP} ${PORTAGE_STRIP_FLAGS}" banner=true @@ -284,9 +308,9 @@ do ${STRIP} -g "${x}" fi elif [[ ${f} == *"SB executable"* || ${f} == *"SB shared object"* ]] ; then - process_elf "${x}" ${PORTAGE_STRIP_FLAGS} + process_elf "${x}" "${inode_link}" ${PORTAGE_STRIP_FLAGS} elif [[ ${f} == *"SB relocatable"* ]] ; then - process_elf "${x}" ${SAFE_STRIP_FLAGS} + process_elf "${x}" "${inode_link}" ${SAFE_STRIP_FLAGS} fi if ${was_not_writable} ; then @@ -294,6 +318,8 @@ do fi ) & __multijob_post_fork + +done < "${inode_link}" done # With a bit more work, we could run the rsync processes below in -- cgit v1.2.3-1-g7c22