https://github.com/torvalds/linux
Revision 28557cc106e6d2aa8b8c5c7687ea9f8055ff3911 authored by Sebastian Andrzej Siewior on 28 June 2018, 06:26:05 UTC, committed by Linus Torvalds on 28 June 2018, 18:16:44 UTC
Revert commit c7f26ccfb2c3 ("mm/vmstat.c: fix vmstat_update() preemption BUG"). Steven saw a "using smp_processor_id() in preemptible" message and added a preempt_disable() section around it to keep it quiet. This is not the right thing to do it does not fix the real problem. vmstat_update() is invoked by a kworker on a specific CPU. This worker it bound to this CPU. The name of the worker was "kworker/1:1" so it should have been a worker which was bound to CPU1. A worker which can run on any CPU would have a `u' before the first digit. smp_processor_id() can be used in a preempt-enabled region as long as the task is bound to a single CPU which is the case here. If it could run on an arbitrary CPU then this is the problem we have an should seek to resolve. Not only this smp_processor_id() must not be migrated to another CPU but also refresh_cpu_vm_stats() which might access wrong per-CPU variables. Not to mention that other code relies on the fact that such a worker runs on one specific CPU only. Therefore revert that commit and we should look instead what broke the affinity mask of the kworker. Link: http://lkml.kernel.org/r/20180504104451.20278-1-bigeasy@linutronix.de Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Cc: Steven J. Hill <steven.hill@cavium.com> Cc: Tejun Heo <htejun@gmail.com> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 4bb6e96
Tip revision: 28557cc106e6d2aa8b8c5c7687ea9f8055ff3911 authored by Sebastian Andrzej Siewior on 28 June 2018, 06:26:05 UTC
Revert mm/vmstat.c: fix vmstat_update() preemption BUG
Revert mm/vmstat.c: fix vmstat_update() preemption BUG
Tip revision: 28557cc
faddr2line
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Translate stack dump function offsets.
#
# addr2line doesn't work with KASLR addresses. This works similarly to
# addr2line, but instead takes the 'func+0x123' format as input:
#
# $ ./scripts/faddr2line ~/k/vmlinux meminfo_proc_show+0x5/0x568
# meminfo_proc_show+0x5/0x568:
# meminfo_proc_show at fs/proc/meminfo.c:27
#
# If the address is part of an inlined function, the full inline call chain is
# printed:
#
# $ ./scripts/faddr2line ~/k/vmlinux native_write_msr+0x6/0x27
# native_write_msr+0x6/0x27:
# arch_static_branch at arch/x86/include/asm/msr.h:121
# (inlined by) static_key_false at include/linux/jump_label.h:125
# (inlined by) native_write_msr at arch/x86/include/asm/msr.h:125
#
# The function size after the '/' in the input is optional, but recommended.
# It's used to help disambiguate any duplicate symbol names, which can occur
# rarely. If the size is omitted for a duplicate symbol then it's possible for
# multiple code sites to be printed:
#
# $ ./scripts/faddr2line ~/k/vmlinux raw_ioctl+0x5
# raw_ioctl+0x5/0x20:
# raw_ioctl at drivers/char/raw.c:122
#
# raw_ioctl+0x5/0xb1:
# raw_ioctl at net/ipv4/raw.c:876
#
# Multiple addresses can be specified on a single command line:
#
# $ ./scripts/faddr2line ~/k/vmlinux type_show+0x10/45 free_reserved_area+0x90
# type_show+0x10/0x2d:
# type_show at drivers/video/backlight/backlight.c:213
#
# free_reserved_area+0x90/0x123:
# free_reserved_area at mm/page_alloc.c:6429 (discriminator 2)
set -o errexit
set -o nounset
READELF="${CROSS_COMPILE:-}readelf"
ADDR2LINE="${CROSS_COMPILE:-}addr2line"
SIZE="${CROSS_COMPILE:-}size"
NM="${CROSS_COMPILE:-}nm"
command -v awk >/dev/null 2>&1 || die "awk isn't installed"
command -v ${READELF} >/dev/null 2>&1 || die "readelf isn't installed"
command -v ${ADDR2LINE} >/dev/null 2>&1 || die "addr2line isn't installed"
command -v ${SIZE} >/dev/null 2>&1 || die "size isn't installed"
command -v ${NM} >/dev/null 2>&1 || die "nm isn't installed"
usage() {
echo "usage: faddr2line [--list] <object file> <func+offset> <func+offset>..." >&2
exit 1
}
warn() {
echo "$1" >&2
}
die() {
echo "ERROR: $1" >&2
exit 1
}
# Try to figure out the source directory prefix so we can remove it from the
# addr2line output. HACK ALERT: This assumes that start_kernel() is in
# kernel/init.c! This only works for vmlinux. Otherwise it falls back to
# printing the absolute path.
find_dir_prefix() {
local objfile=$1
local start_kernel_addr=$(${READELF} -sW $objfile | awk '$8 == "start_kernel" {printf "0x%s", $2}')
[[ -z $start_kernel_addr ]] && return
local file_line=$(${ADDR2LINE} -e $objfile $start_kernel_addr)
[[ -z $file_line ]] && return
local prefix=${file_line%init/main.c:*}
if [[ -z $prefix ]] || [[ $prefix = $file_line ]]; then
return
fi
DIR_PREFIX=$prefix
return 0
}
__faddr2line() {
local objfile=$1
local func_addr=$2
local dir_prefix=$3
local print_warnings=$4
local func=${func_addr%+*}
local offset=${func_addr#*+}
offset=${offset%/*}
local size=
[[ $func_addr =~ "/" ]] && size=${func_addr#*/}
if [[ -z $func ]] || [[ -z $offset ]] || [[ $func = $func_addr ]]; then
warn "bad func+offset $func_addr"
DONE=1
return
fi
# Go through each of the object's symbols which match the func name.
# In rare cases there might be duplicates.
file_end=$(${SIZE} -Ax $objfile | awk '$1 == ".text" {print $2}')
while read symbol; do
local fields=($symbol)
local sym_base=0x${fields[0]}
local sym_type=${fields[1]}
local sym_end=${fields[3]}
# calculate the size
local sym_size=$(($sym_end - $sym_base))
if [[ -z $sym_size ]] || [[ $sym_size -le 0 ]]; then
warn "bad symbol size: base: $sym_base end: $sym_end"
DONE=1
return
fi
sym_size=0x$(printf %x $sym_size)
# calculate the address
local addr=$(($sym_base + $offset))
if [[ -z $addr ]] || [[ $addr = 0 ]]; then
warn "bad address: $sym_base + $offset"
DONE=1
return
fi
addr=0x$(printf %x $addr)
# weed out non-function symbols
if [[ $sym_type != t ]] && [[ $sym_type != T ]]; then
[[ $print_warnings = 1 ]] &&
echo "skipping $func address at $addr due to non-function symbol of type '$sym_type'"
continue
fi
# if the user provided a size, make sure it matches the symbol's size
if [[ -n $size ]] && [[ $size -ne $sym_size ]]; then
[[ $print_warnings = 1 ]] &&
echo "skipping $func address at $addr due to size mismatch ($size != $sym_size)"
continue;
fi
# make sure the provided offset is within the symbol's range
if [[ $offset -gt $sym_size ]]; then
[[ $print_warnings = 1 ]] &&
echo "skipping $func address at $addr due to size mismatch ($offset > $sym_size)"
continue
fi
# separate multiple entries with a blank line
[[ $FIRST = 0 ]] && echo
FIRST=0
# pass real address to addr2line
echo "$func+$offset/$sym_size:"
local file_lines=$(${ADDR2LINE} -fpie $objfile $addr | sed "s; $dir_prefix\(\./\)*; ;")
[[ -z $file_lines ]] && return
if [[ $LIST = 0 ]]; then
echo "$file_lines" | while read -r line
do
echo $line
done
DONE=1;
return
fi
# show each line with context
echo "$file_lines" | while read -r line
do
echo
echo $line
n=$(echo $line | sed 's/.*:\([0-9]\+\).*/\1/g')
n1=$[$n-5]
n2=$[$n+5]
f=$(echo $line | sed 's/.*at \(.\+\):.*/\1/g')
awk 'NR>=strtonum("'$n1'") && NR<=strtonum("'$n2'") { if (NR=='$n') printf(">%d<", NR); else printf(" %d ", NR); printf("\t%s\n", $0)}' $f
done
DONE=1
done < <(${NM} -n $objfile | awk -v fn=$func -v end=$file_end '$3 == fn { found=1; line=$0; start=$1; next } found == 1 { found=0; print line, "0x"$1 } END {if (found == 1) print line, end; }')
}
[[ $# -lt 2 ]] && usage
objfile=$1
LIST=0
[[ "$objfile" == "--list" ]] && LIST=1 && shift && objfile=$1
[[ ! -f $objfile ]] && die "can't find objfile $objfile"
shift
DIR_PREFIX=supercalifragilisticexpialidocious
find_dir_prefix $objfile
FIRST=1
while [[ $# -gt 0 ]]; do
func_addr=$1
shift
# print any matches found
DONE=0
__faddr2line $objfile $func_addr $DIR_PREFIX 0
# if no match was found, print warnings
if [[ $DONE = 0 ]]; then
__faddr2line $objfile $func_addr $DIR_PREFIX 1
warn "no match for $func_addr"
fi
done
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...