forked from Minki/linux
Tracing fixes for 5.10-rc6
- Use correct timestamp variable for ring buffer write stamp update - Fix up before stamp and write stamp when crossing ring buffer sub buffers - Keep a zero delta in ring buffer in slow path if cmpxchg fails - Fix trace_printk static buffer for archs that care - Fix ftrace record accounting for ftrace ops with trampolines - Fix DYNAMIC_FTRACE_WITH_DIRECT_CALLS dependency - Remove WARN_ON in hwlat tracer that triggers on something that is OK - Make "my_tramp" trampoline in ftrace direct sample code global - Fixes in the bootconfig tool for better alignment management -----BEGIN PGP SIGNATURE----- iIoEABYIADIWIQRRSw7ePDh/lE+zeZMp5XQQmuv6qgUCX8ZzghQccm9zdGVkdEBn b29kbWlzLm9yZwAKCRAp5XQQmuv6qg0JAQCII1bDQyF3APLlNFRqfHf3bTo7Zl5z WaUd1Cd7JkY+WAD/eF1dWjN0JRtfU+oRlk6UZ4oNmp8WMJvQ7oV26ub2egE= =lts8 -----END PGP SIGNATURE----- Merge tag 'trace-v5.10-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace Pull tracing fixes from Steven Rostedt: - Use correct timestamp variable for ring buffer write stamp update - Fix up before stamp and write stamp when crossing ring buffer sub buffers - Keep a zero delta in ring buffer in slow path if cmpxchg fails - Fix trace_printk static buffer for archs that care - Fix ftrace record accounting for ftrace ops with trampolines - Fix DYNAMIC_FTRACE_WITH_DIRECT_CALLS dependency - Remove WARN_ON in hwlat tracer that triggers on something that is OK - Make "my_tramp" trampoline in ftrace direct sample code global - Fixes in the bootconfig tool for better alignment management * tag 'trace-v5.10-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: ring-buffer: Always check to put back before stamp when crossing pages ftrace: Fix DYNAMIC_FTRACE_WITH_DIRECT_CALLS dependency ftrace: Fix updating FTRACE_FL_TRAMP tracing: Fix alignment of static buffer tracing: Remove WARN_ON in start_thread() samples/ftrace: Mark my_tramp[12]? global ring-buffer: Set the right timestamp in the slow path of __rb_reserve_next() ring-buffer: Update write stamp with the correct ts docs: bootconfig: Update file format on initrd image tools/bootconfig: Align the bootconfig applied initrd image size to 4 tools/bootconfig: Fix to check the write failure correctly tools/bootconfig: Fix errno reference after printf()
This commit is contained in:
commit
ef6900acc8
@ -137,15 +137,22 @@ Boot Kernel With a Boot Config
|
||||
==============================
|
||||
|
||||
Since the boot configuration file is loaded with initrd, it will be added
|
||||
to the end of the initrd (initramfs) image file with size, checksum and
|
||||
12-byte magic word as below.
|
||||
to the end of the initrd (initramfs) image file with padding, size,
|
||||
checksum and 12-byte magic word as below.
|
||||
|
||||
[initrd][bootconfig][size(u32)][checksum(u32)][#BOOTCONFIG\n]
|
||||
[initrd][bootconfig][padding][size(u32)][checksum(u32)][#BOOTCONFIG\n]
|
||||
|
||||
When the boot configuration is added to the initrd image, the total
|
||||
file size is aligned to 4 bytes. To fill the gap, null characters
|
||||
(``\0``) will be added. Thus the ``size`` is the length of the bootconfig
|
||||
file + padding bytes.
|
||||
|
||||
The Linux kernel decodes the last part of the initrd image in memory to
|
||||
get the boot configuration data.
|
||||
Because of this "piggyback" method, there is no need to change or
|
||||
update the boot loader and the kernel image itself.
|
||||
update the boot loader and the kernel image itself as long as the boot
|
||||
loader passes the correct initrd file size. If by any chance, the boot
|
||||
loader passes a longer size, the kernel feils to find the bootconfig data.
|
||||
|
||||
To do this operation, Linux kernel provides "bootconfig" command under
|
||||
tools/bootconfig, which allows admin to apply or delete the config file
|
||||
@ -176,7 +183,8 @@ up to 512 key-value pairs. If keys contains 3 words in average, it can
|
||||
contain 256 key-value pairs. In most cases, the number of config items
|
||||
will be under 100 entries and smaller than 8KB, so it would be enough.
|
||||
If the node number exceeds 1024, parser returns an error even if the file
|
||||
size is smaller than 32KB.
|
||||
size is smaller than 32KB. (Note that this maximum size is not including
|
||||
the padding null characters.)
|
||||
Anyway, since bootconfig command verifies it when appending a boot config
|
||||
to initrd image, user can notice it before boot.
|
||||
|
||||
|
@ -12,6 +12,9 @@
|
||||
|
||||
#define BOOTCONFIG_MAGIC "#BOOTCONFIG\n"
|
||||
#define BOOTCONFIG_MAGIC_LEN 12
|
||||
#define BOOTCONFIG_ALIGN_SHIFT 2
|
||||
#define BOOTCONFIG_ALIGN (1 << BOOTCONFIG_ALIGN_SHIFT)
|
||||
#define BOOTCONFIG_ALIGN_MASK (BOOTCONFIG_ALIGN - 1)
|
||||
|
||||
/* XBC tree node */
|
||||
struct xbc_node {
|
||||
|
@ -202,7 +202,7 @@ config DYNAMIC_FTRACE_WITH_REGS
|
||||
|
||||
config DYNAMIC_FTRACE_WITH_DIRECT_CALLS
|
||||
def_bool y
|
||||
depends on DYNAMIC_FTRACE
|
||||
depends on DYNAMIC_FTRACE_WITH_REGS
|
||||
depends on HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
|
||||
|
||||
config FUNCTION_PROFILER
|
||||
|
@ -1629,6 +1629,8 @@ static bool test_rec_ops_needs_regs(struct dyn_ftrace *rec)
|
||||
static struct ftrace_ops *
|
||||
ftrace_find_tramp_ops_any(struct dyn_ftrace *rec);
|
||||
static struct ftrace_ops *
|
||||
ftrace_find_tramp_ops_any_other(struct dyn_ftrace *rec, struct ftrace_ops *op_exclude);
|
||||
static struct ftrace_ops *
|
||||
ftrace_find_tramp_ops_next(struct dyn_ftrace *rec, struct ftrace_ops *ops);
|
||||
|
||||
static bool __ftrace_hash_rec_update(struct ftrace_ops *ops,
|
||||
@ -1778,7 +1780,7 @@ static bool __ftrace_hash_rec_update(struct ftrace_ops *ops,
|
||||
* to it.
|
||||
*/
|
||||
if (ftrace_rec_count(rec) == 1 &&
|
||||
ftrace_find_tramp_ops_any(rec))
|
||||
ftrace_find_tramp_ops_any_other(rec, ops))
|
||||
rec->flags |= FTRACE_FL_TRAMP;
|
||||
else
|
||||
rec->flags &= ~FTRACE_FL_TRAMP;
|
||||
@ -2244,6 +2246,24 @@ ftrace_find_tramp_ops_any(struct dyn_ftrace *rec)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ftrace_ops *
|
||||
ftrace_find_tramp_ops_any_other(struct dyn_ftrace *rec, struct ftrace_ops *op_exclude)
|
||||
{
|
||||
struct ftrace_ops *op;
|
||||
unsigned long ip = rec->ip;
|
||||
|
||||
do_for_each_ftrace_op(op, ftrace_ops_list) {
|
||||
|
||||
if (op == op_exclude || !op->trampoline)
|
||||
continue;
|
||||
|
||||
if (hash_contains_ip(ip, op->func_hash))
|
||||
return op;
|
||||
} while_for_each_ftrace_op(op);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ftrace_ops *
|
||||
ftrace_find_tramp_ops_next(struct dyn_ftrace *rec,
|
||||
struct ftrace_ops *op)
|
||||
|
@ -3234,14 +3234,12 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
|
||||
|
||||
/* See if we shot pass the end of this buffer page */
|
||||
if (unlikely(write > BUF_PAGE_SIZE)) {
|
||||
if (tail != w) {
|
||||
/* before and after may now different, fix it up*/
|
||||
b_ok = rb_time_read(&cpu_buffer->before_stamp, &info->before);
|
||||
a_ok = rb_time_read(&cpu_buffer->write_stamp, &info->after);
|
||||
if (a_ok && b_ok && info->before != info->after)
|
||||
(void)rb_time_cmpxchg(&cpu_buffer->before_stamp,
|
||||
info->before, info->after);
|
||||
}
|
||||
/* before and after may now different, fix it up*/
|
||||
b_ok = rb_time_read(&cpu_buffer->before_stamp, &info->before);
|
||||
a_ok = rb_time_read(&cpu_buffer->write_stamp, &info->after);
|
||||
if (a_ok && b_ok && info->before != info->after)
|
||||
(void)rb_time_cmpxchg(&cpu_buffer->before_stamp,
|
||||
info->before, info->after);
|
||||
return rb_move_tail(cpu_buffer, tail, info);
|
||||
}
|
||||
|
||||
@ -3287,11 +3285,11 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
|
||||
ts = rb_time_stamp(cpu_buffer->buffer);
|
||||
barrier();
|
||||
/*E*/ if (write == (local_read(&tail_page->write) & RB_WRITE_MASK) &&
|
||||
info->after < ts) {
|
||||
info->after < ts &&
|
||||
rb_time_cmpxchg(&cpu_buffer->write_stamp,
|
||||
info->after, ts)) {
|
||||
/* Nothing came after this event between C and E */
|
||||
info->delta = ts - info->after;
|
||||
(void)rb_time_cmpxchg(&cpu_buffer->write_stamp,
|
||||
info->after, info->ts);
|
||||
info->ts = ts;
|
||||
} else {
|
||||
/*
|
||||
|
@ -3534,7 +3534,7 @@ __find_next_entry(struct trace_iterator *iter, int *ent_cpu,
|
||||
}
|
||||
|
||||
#define STATIC_TEMP_BUF_SIZE 128
|
||||
static char static_temp_buf[STATIC_TEMP_BUF_SIZE];
|
||||
static char static_temp_buf[STATIC_TEMP_BUF_SIZE] __aligned(4);
|
||||
|
||||
/* Find the next real entry, without updating the iterator itself */
|
||||
struct trace_entry *trace_find_next_entry(struct trace_iterator *iter,
|
||||
|
@ -368,7 +368,7 @@ static int start_kthread(struct trace_array *tr)
|
||||
struct task_struct *kthread;
|
||||
int next_cpu;
|
||||
|
||||
if (WARN_ON(hwlat_kthread))
|
||||
if (hwlat_kthread)
|
||||
return 0;
|
||||
|
||||
/* Just pick the first CPU on first iteration */
|
||||
|
@ -21,6 +21,7 @@ static unsigned long my_ip = (unsigned long)schedule;
|
||||
asm (
|
||||
" .pushsection .text, \"ax\", @progbits\n"
|
||||
" .type my_tramp1, @function\n"
|
||||
" .globl my_tramp1\n"
|
||||
" my_tramp1:"
|
||||
" pushq %rbp\n"
|
||||
" movq %rsp, %rbp\n"
|
||||
@ -29,6 +30,7 @@ asm (
|
||||
" .size my_tramp1, .-my_tramp1\n"
|
||||
" ret\n"
|
||||
" .type my_tramp2, @function\n"
|
||||
" .globl my_tramp2\n"
|
||||
" my_tramp2:"
|
||||
" pushq %rbp\n"
|
||||
" movq %rsp, %rbp\n"
|
||||
|
@ -16,6 +16,7 @@ extern void my_tramp(void *);
|
||||
asm (
|
||||
" .pushsection .text, \"ax\", @progbits\n"
|
||||
" .type my_tramp, @function\n"
|
||||
" .globl my_tramp\n"
|
||||
" my_tramp:"
|
||||
" pushq %rbp\n"
|
||||
" movq %rsp, %rbp\n"
|
||||
|
@ -14,6 +14,7 @@ extern void my_tramp(void *);
|
||||
asm (
|
||||
" .pushsection .text, \"ax\", @progbits\n"
|
||||
" .type my_tramp, @function\n"
|
||||
" .globl my_tramp\n"
|
||||
" my_tramp:"
|
||||
" pushq %rbp\n"
|
||||
" movq %rsp, %rbp\n"
|
||||
|
@ -147,6 +147,12 @@ static int load_xbc_file(const char *path, char **buf)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pr_errno(const char *msg, int err)
|
||||
{
|
||||
pr_err("%s: %d\n", msg, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int load_xbc_from_initrd(int fd, char **buf)
|
||||
{
|
||||
struct stat stat;
|
||||
@ -162,26 +168,24 @@ static int load_xbc_from_initrd(int fd, char **buf)
|
||||
if (stat.st_size < 8 + BOOTCONFIG_MAGIC_LEN)
|
||||
return 0;
|
||||
|
||||
if (lseek(fd, -BOOTCONFIG_MAGIC_LEN, SEEK_END) < 0) {
|
||||
pr_err("Failed to lseek: %d\n", -errno);
|
||||
return -errno;
|
||||
}
|
||||
if (lseek(fd, -BOOTCONFIG_MAGIC_LEN, SEEK_END) < 0)
|
||||
return pr_errno("Failed to lseek for magic", -errno);
|
||||
|
||||
if (read(fd, magic, BOOTCONFIG_MAGIC_LEN) < 0)
|
||||
return -errno;
|
||||
return pr_errno("Failed to read", -errno);
|
||||
|
||||
/* Check the bootconfig magic bytes */
|
||||
if (memcmp(magic, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN) != 0)
|
||||
return 0;
|
||||
|
||||
if (lseek(fd, -(8 + BOOTCONFIG_MAGIC_LEN), SEEK_END) < 0) {
|
||||
pr_err("Failed to lseek: %d\n", -errno);
|
||||
return -errno;
|
||||
}
|
||||
if (lseek(fd, -(8 + BOOTCONFIG_MAGIC_LEN), SEEK_END) < 0)
|
||||
return pr_errno("Failed to lseek for size", -errno);
|
||||
|
||||
if (read(fd, &size, sizeof(u32)) < 0)
|
||||
return -errno;
|
||||
return pr_errno("Failed to read size", -errno);
|
||||
|
||||
if (read(fd, &csum, sizeof(u32)) < 0)
|
||||
return -errno;
|
||||
return pr_errno("Failed to read checksum", -errno);
|
||||
|
||||
/* Wrong size error */
|
||||
if (stat.st_size < size + 8 + BOOTCONFIG_MAGIC_LEN) {
|
||||
@ -190,10 +194,8 @@ static int load_xbc_from_initrd(int fd, char **buf)
|
||||
}
|
||||
|
||||
if (lseek(fd, stat.st_size - (size + 8 + BOOTCONFIG_MAGIC_LEN),
|
||||
SEEK_SET) < 0) {
|
||||
pr_err("Failed to lseek: %d\n", -errno);
|
||||
return -errno;
|
||||
}
|
||||
SEEK_SET) < 0)
|
||||
return pr_errno("Failed to lseek", -errno);
|
||||
|
||||
ret = load_xbc_fd(fd, buf, size);
|
||||
if (ret < 0)
|
||||
@ -262,14 +264,16 @@ static int show_xbc(const char *path, bool list)
|
||||
|
||||
ret = stat(path, &st);
|
||||
if (ret < 0) {
|
||||
pr_err("Failed to stat %s: %d\n", path, -errno);
|
||||
return -errno;
|
||||
ret = -errno;
|
||||
pr_err("Failed to stat %s: %d\n", path, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
pr_err("Failed to open initrd %s: %d\n", path, fd);
|
||||
return -errno;
|
||||
ret = -errno;
|
||||
pr_err("Failed to open initrd %s: %d\n", path, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = load_xbc_from_initrd(fd, &buf);
|
||||
@ -307,8 +311,9 @@ static int delete_xbc(const char *path)
|
||||
|
||||
fd = open(path, O_RDWR);
|
||||
if (fd < 0) {
|
||||
pr_err("Failed to open initrd %s: %d\n", path, fd);
|
||||
return -errno;
|
||||
ret = -errno;
|
||||
pr_err("Failed to open initrd %s: %d\n", path, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size = load_xbc_from_initrd(fd, &buf);
|
||||
@ -332,11 +337,13 @@ static int delete_xbc(const char *path)
|
||||
|
||||
static int apply_xbc(const char *path, const char *xbc_path)
|
||||
{
|
||||
u32 size, csum;
|
||||
char *buf, *data;
|
||||
int ret, fd;
|
||||
char *buf, *data, *p;
|
||||
size_t total_size;
|
||||
struct stat stat;
|
||||
const char *msg;
|
||||
int pos;
|
||||
u32 size, csum;
|
||||
int pos, pad;
|
||||
int ret, fd;
|
||||
|
||||
ret = load_xbc_file(xbc_path, &buf);
|
||||
if (ret < 0) {
|
||||
@ -346,13 +353,12 @@ static int apply_xbc(const char *path, const char *xbc_path)
|
||||
size = strlen(buf) + 1;
|
||||
csum = checksum((unsigned char *)buf, size);
|
||||
|
||||
/* Prepare xbc_path data */
|
||||
data = malloc(size + 8);
|
||||
/* Backup the bootconfig data */
|
||||
data = calloc(size + BOOTCONFIG_ALIGN +
|
||||
sizeof(u32) + sizeof(u32) + BOOTCONFIG_MAGIC_LEN, 1);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
strcpy(data, buf);
|
||||
*(u32 *)(data + size) = size;
|
||||
*(u32 *)(data + size + 4) = csum;
|
||||
memcpy(data, buf, size);
|
||||
|
||||
/* Check the data format */
|
||||
ret = xbc_init(buf, &msg, &pos);
|
||||
@ -383,28 +389,61 @@ static int apply_xbc(const char *path, const char *xbc_path)
|
||||
/* Apply new one */
|
||||
fd = open(path, O_RDWR | O_APPEND);
|
||||
if (fd < 0) {
|
||||
pr_err("Failed to open %s: %d\n", path, fd);
|
||||
ret = -errno;
|
||||
pr_err("Failed to open %s: %d\n", path, ret);
|
||||
free(data);
|
||||
return fd;
|
||||
return ret;
|
||||
}
|
||||
/* TODO: Ensure the @path is initramfs/initrd image */
|
||||
ret = write(fd, data, size + 8);
|
||||
if (ret < 0) {
|
||||
if (fstat(fd, &stat) < 0) {
|
||||
pr_err("Failed to get the size of %s\n", path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* To align up the total size to BOOTCONFIG_ALIGN, get padding size */
|
||||
total_size = stat.st_size + size + sizeof(u32) * 2 + BOOTCONFIG_MAGIC_LEN;
|
||||
pad = ((total_size + BOOTCONFIG_ALIGN - 1) & (~BOOTCONFIG_ALIGN_MASK)) - total_size;
|
||||
size += pad;
|
||||
|
||||
/* Add a footer */
|
||||
p = data + size;
|
||||
*(u32 *)p = size;
|
||||
p += sizeof(u32);
|
||||
|
||||
*(u32 *)p = csum;
|
||||
p += sizeof(u32);
|
||||
|
||||
memcpy(p, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN);
|
||||
p += BOOTCONFIG_MAGIC_LEN;
|
||||
|
||||
total_size = p - data;
|
||||
|
||||
ret = write(fd, data, total_size);
|
||||
if (ret < total_size) {
|
||||
if (ret < 0)
|
||||
ret = -errno;
|
||||
pr_err("Failed to apply a boot config: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
/* Write a magic word of the bootconfig */
|
||||
ret = write(fd, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN);
|
||||
if (ret < 0) {
|
||||
pr_err("Failed to apply a boot config magic: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
ret = 0;
|
||||
if (ret >= 0)
|
||||
goto out_rollback;
|
||||
} else
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
close(fd);
|
||||
free(data);
|
||||
|
||||
return ret;
|
||||
|
||||
out_rollback:
|
||||
/* Map the partial write to -ENOSPC */
|
||||
if (ret >= 0)
|
||||
ret = -ENOSPC;
|
||||
if (ftruncate(fd, stat.st_size) < 0) {
|
||||
ret = -errno;
|
||||
pr_err("Failed to rollback the write error: %d\n", ret);
|
||||
pr_err("The initrd %s may be corrupted. Recommend to rebuild.\n", path);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
static int usage(void)
|
||||
|
@ -9,6 +9,7 @@ else
|
||||
TESTDIR=.
|
||||
fi
|
||||
BOOTCONF=${TESTDIR}/bootconfig
|
||||
ALIGN=4
|
||||
|
||||
INITRD=`mktemp ${TESTDIR}/initrd-XXXX`
|
||||
TEMPCONF=`mktemp ${TESTDIR}/temp-XXXX.bconf`
|
||||
@ -59,7 +60,10 @@ echo "Show command test"
|
||||
xpass $BOOTCONF $INITRD
|
||||
|
||||
echo "File size check"
|
||||
xpass test $new_size -eq $(expr $bconf_size + $initrd_size + 9 + 12)
|
||||
total_size=$(expr $bconf_size + $initrd_size + 9 + 12 + $ALIGN - 1 )
|
||||
total_size=$(expr $total_size / $ALIGN)
|
||||
total_size=$(expr $total_size \* $ALIGN)
|
||||
xpass test $new_size -eq $total_size
|
||||
|
||||
echo "Apply command repeat test"
|
||||
xpass $BOOTCONF -a $TEMPCONF $INITRD
|
||||
|
Loading…
Reference in New Issue
Block a user