prepstrip: account for new inode created by strip
authorZac Medico <zmedico@gentoo.org>
Mon, 5 Nov 2012 02:51:20 +0000 (18:51 -0800)
committerZac Medico <zmedico@gentoo.org>
Mon, 5 Nov 2012 02:51:20 +0000 (18:51 -0800)
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

index 0d1ce5a092b66f98689bdb7b0e2651232c59fbae..c6bf60e1d62e56af8463c0eda76acce6e3a58ac1 100755 (executable)
@@ -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 <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