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()zero-sugar-mainline-defconfig
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
|
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
|
to the end of the initrd (initramfs) image file with padding, size,
|
||||||
12-byte magic word as below.
|
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
|
The Linux kernel decodes the last part of the initrd image in memory to
|
||||||
get the boot configuration data.
|
get the boot configuration data.
|
||||||
Because of this "piggyback" method, there is no need to change or
|
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
|
To do this operation, Linux kernel provides "bootconfig" command under
|
||||||
tools/bootconfig, which allows admin to apply or delete the config file
|
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
|
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.
|
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
|
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
|
Anyway, since bootconfig command verifies it when appending a boot config
|
||||||
to initrd image, user can notice it before boot.
|
to initrd image, user can notice it before boot.
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,9 @@
|
||||||
|
|
||||||
#define BOOTCONFIG_MAGIC "#BOOTCONFIG\n"
|
#define BOOTCONFIG_MAGIC "#BOOTCONFIG\n"
|
||||||
#define BOOTCONFIG_MAGIC_LEN 12
|
#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 */
|
/* XBC tree node */
|
||||||
struct xbc_node {
|
struct xbc_node {
|
||||||
|
|
|
@ -202,7 +202,7 @@ config DYNAMIC_FTRACE_WITH_REGS
|
||||||
|
|
||||||
config DYNAMIC_FTRACE_WITH_DIRECT_CALLS
|
config DYNAMIC_FTRACE_WITH_DIRECT_CALLS
|
||||||
def_bool y
|
def_bool y
|
||||||
depends on DYNAMIC_FTRACE
|
depends on DYNAMIC_FTRACE_WITH_REGS
|
||||||
depends on HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
|
depends on HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
|
||||||
|
|
||||||
config FUNCTION_PROFILER
|
config FUNCTION_PROFILER
|
||||||
|
|
|
@ -1629,6 +1629,8 @@ static bool test_rec_ops_needs_regs(struct dyn_ftrace *rec)
|
||||||
static struct ftrace_ops *
|
static struct ftrace_ops *
|
||||||
ftrace_find_tramp_ops_any(struct dyn_ftrace *rec);
|
ftrace_find_tramp_ops_any(struct dyn_ftrace *rec);
|
||||||
static struct ftrace_ops *
|
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);
|
ftrace_find_tramp_ops_next(struct dyn_ftrace *rec, struct ftrace_ops *ops);
|
||||||
|
|
||||||
static bool __ftrace_hash_rec_update(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.
|
* to it.
|
||||||
*/
|
*/
|
||||||
if (ftrace_rec_count(rec) == 1 &&
|
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;
|
rec->flags |= FTRACE_FL_TRAMP;
|
||||||
else
|
else
|
||||||
rec->flags &= ~FTRACE_FL_TRAMP;
|
rec->flags &= ~FTRACE_FL_TRAMP;
|
||||||
|
@ -2244,6 +2246,24 @@ ftrace_find_tramp_ops_any(struct dyn_ftrace *rec)
|
||||||
return NULL;
|
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 *
|
static struct ftrace_ops *
|
||||||
ftrace_find_tramp_ops_next(struct dyn_ftrace *rec,
|
ftrace_find_tramp_ops_next(struct dyn_ftrace *rec,
|
||||||
struct ftrace_ops *op)
|
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 */
|
/* See if we shot pass the end of this buffer page */
|
||||||
if (unlikely(write > BUF_PAGE_SIZE)) {
|
if (unlikely(write > BUF_PAGE_SIZE)) {
|
||||||
if (tail != w) {
|
/* before and after may now different, fix it up*/
|
||||||
/* before and after may now different, fix it up*/
|
b_ok = rb_time_read(&cpu_buffer->before_stamp, &info->before);
|
||||||
b_ok = rb_time_read(&cpu_buffer->before_stamp, &info->before);
|
a_ok = rb_time_read(&cpu_buffer->write_stamp, &info->after);
|
||||||
a_ok = rb_time_read(&cpu_buffer->write_stamp, &info->after);
|
if (a_ok && b_ok && info->before != info->after)
|
||||||
if (a_ok && b_ok && info->before != info->after)
|
(void)rb_time_cmpxchg(&cpu_buffer->before_stamp,
|
||||||
(void)rb_time_cmpxchg(&cpu_buffer->before_stamp,
|
info->before, info->after);
|
||||||
info->before, info->after);
|
|
||||||
}
|
|
||||||
return rb_move_tail(cpu_buffer, tail, info);
|
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);
|
ts = rb_time_stamp(cpu_buffer->buffer);
|
||||||
barrier();
|
barrier();
|
||||||
/*E*/ if (write == (local_read(&tail_page->write) & RB_WRITE_MASK) &&
|
/*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 */
|
/* Nothing came after this event between C and E */
|
||||||
info->delta = ts - info->after;
|
info->delta = ts - info->after;
|
||||||
(void)rb_time_cmpxchg(&cpu_buffer->write_stamp,
|
|
||||||
info->after, info->ts);
|
|
||||||
info->ts = ts;
|
info->ts = ts;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -3534,7 +3534,7 @@ __find_next_entry(struct trace_iterator *iter, int *ent_cpu,
|
||||||
}
|
}
|
||||||
|
|
||||||
#define STATIC_TEMP_BUF_SIZE 128
|
#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 */
|
/* Find the next real entry, without updating the iterator itself */
|
||||||
struct trace_entry *trace_find_next_entry(struct trace_iterator *iter,
|
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;
|
struct task_struct *kthread;
|
||||||
int next_cpu;
|
int next_cpu;
|
||||||
|
|
||||||
if (WARN_ON(hwlat_kthread))
|
if (hwlat_kthread)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Just pick the first CPU on first iteration */
|
/* Just pick the first CPU on first iteration */
|
||||||
|
|
|
@ -21,6 +21,7 @@ static unsigned long my_ip = (unsigned long)schedule;
|
||||||
asm (
|
asm (
|
||||||
" .pushsection .text, \"ax\", @progbits\n"
|
" .pushsection .text, \"ax\", @progbits\n"
|
||||||
" .type my_tramp1, @function\n"
|
" .type my_tramp1, @function\n"
|
||||||
|
" .globl my_tramp1\n"
|
||||||
" my_tramp1:"
|
" my_tramp1:"
|
||||||
" pushq %rbp\n"
|
" pushq %rbp\n"
|
||||||
" movq %rsp, %rbp\n"
|
" movq %rsp, %rbp\n"
|
||||||
|
@ -29,6 +30,7 @@ asm (
|
||||||
" .size my_tramp1, .-my_tramp1\n"
|
" .size my_tramp1, .-my_tramp1\n"
|
||||||
" ret\n"
|
" ret\n"
|
||||||
" .type my_tramp2, @function\n"
|
" .type my_tramp2, @function\n"
|
||||||
|
" .globl my_tramp2\n"
|
||||||
" my_tramp2:"
|
" my_tramp2:"
|
||||||
" pushq %rbp\n"
|
" pushq %rbp\n"
|
||||||
" movq %rsp, %rbp\n"
|
" movq %rsp, %rbp\n"
|
||||||
|
|
|
@ -16,6 +16,7 @@ extern void my_tramp(void *);
|
||||||
asm (
|
asm (
|
||||||
" .pushsection .text, \"ax\", @progbits\n"
|
" .pushsection .text, \"ax\", @progbits\n"
|
||||||
" .type my_tramp, @function\n"
|
" .type my_tramp, @function\n"
|
||||||
|
" .globl my_tramp\n"
|
||||||
" my_tramp:"
|
" my_tramp:"
|
||||||
" pushq %rbp\n"
|
" pushq %rbp\n"
|
||||||
" movq %rsp, %rbp\n"
|
" movq %rsp, %rbp\n"
|
||||||
|
|
|
@ -14,6 +14,7 @@ extern void my_tramp(void *);
|
||||||
asm (
|
asm (
|
||||||
" .pushsection .text, \"ax\", @progbits\n"
|
" .pushsection .text, \"ax\", @progbits\n"
|
||||||
" .type my_tramp, @function\n"
|
" .type my_tramp, @function\n"
|
||||||
|
" .globl my_tramp\n"
|
||||||
" my_tramp:"
|
" my_tramp:"
|
||||||
" pushq %rbp\n"
|
" pushq %rbp\n"
|
||||||
" movq %rsp, %rbp\n"
|
" movq %rsp, %rbp\n"
|
||||||
|
|
|
@ -147,6 +147,12 @@ static int load_xbc_file(const char *path, char **buf)
|
||||||
return ret;
|
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)
|
static int load_xbc_from_initrd(int fd, char **buf)
|
||||||
{
|
{
|
||||||
struct stat stat;
|
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)
|
if (stat.st_size < 8 + BOOTCONFIG_MAGIC_LEN)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (lseek(fd, -BOOTCONFIG_MAGIC_LEN, SEEK_END) < 0) {
|
if (lseek(fd, -BOOTCONFIG_MAGIC_LEN, SEEK_END) < 0)
|
||||||
pr_err("Failed to lseek: %d\n", -errno);
|
return pr_errno("Failed to lseek for magic", -errno);
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
if (read(fd, magic, BOOTCONFIG_MAGIC_LEN) < 0)
|
if (read(fd, magic, BOOTCONFIG_MAGIC_LEN) < 0)
|
||||||
return -errno;
|
return pr_errno("Failed to read", -errno);
|
||||||
|
|
||||||
/* Check the bootconfig magic bytes */
|
/* Check the bootconfig magic bytes */
|
||||||
if (memcmp(magic, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN) != 0)
|
if (memcmp(magic, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (lseek(fd, -(8 + BOOTCONFIG_MAGIC_LEN), SEEK_END) < 0) {
|
if (lseek(fd, -(8 + BOOTCONFIG_MAGIC_LEN), SEEK_END) < 0)
|
||||||
pr_err("Failed to lseek: %d\n", -errno);
|
return pr_errno("Failed to lseek for size", -errno);
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (read(fd, &size, sizeof(u32)) < 0)
|
if (read(fd, &size, sizeof(u32)) < 0)
|
||||||
return -errno;
|
return pr_errno("Failed to read size", -errno);
|
||||||
|
|
||||||
if (read(fd, &csum, sizeof(u32)) < 0)
|
if (read(fd, &csum, sizeof(u32)) < 0)
|
||||||
return -errno;
|
return pr_errno("Failed to read checksum", -errno);
|
||||||
|
|
||||||
/* Wrong size error */
|
/* Wrong size error */
|
||||||
if (stat.st_size < size + 8 + BOOTCONFIG_MAGIC_LEN) {
|
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),
|
if (lseek(fd, stat.st_size - (size + 8 + BOOTCONFIG_MAGIC_LEN),
|
||||||
SEEK_SET) < 0) {
|
SEEK_SET) < 0)
|
||||||
pr_err("Failed to lseek: %d\n", -errno);
|
return pr_errno("Failed to lseek", -errno);
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = load_xbc_fd(fd, buf, size);
|
ret = load_xbc_fd(fd, buf, size);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -262,14 +264,16 @@ static int show_xbc(const char *path, bool list)
|
||||||
|
|
||||||
ret = stat(path, &st);
|
ret = stat(path, &st);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
pr_err("Failed to stat %s: %d\n", path, -errno);
|
ret = -errno;
|
||||||
return -errno;
|
pr_err("Failed to stat %s: %d\n", path, ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = open(path, O_RDONLY);
|
fd = open(path, O_RDONLY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
pr_err("Failed to open initrd %s: %d\n", path, fd);
|
ret = -errno;
|
||||||
return -errno;
|
pr_err("Failed to open initrd %s: %d\n", path, ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = load_xbc_from_initrd(fd, &buf);
|
ret = load_xbc_from_initrd(fd, &buf);
|
||||||
|
@ -307,8 +311,9 @@ static int delete_xbc(const char *path)
|
||||||
|
|
||||||
fd = open(path, O_RDWR);
|
fd = open(path, O_RDWR);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
pr_err("Failed to open initrd %s: %d\n", path, fd);
|
ret = -errno;
|
||||||
return -errno;
|
pr_err("Failed to open initrd %s: %d\n", path, ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = load_xbc_from_initrd(fd, &buf);
|
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)
|
static int apply_xbc(const char *path, const char *xbc_path)
|
||||||
{
|
{
|
||||||
u32 size, csum;
|
char *buf, *data, *p;
|
||||||
char *buf, *data;
|
size_t total_size;
|
||||||
int ret, fd;
|
struct stat stat;
|
||||||
const char *msg;
|
const char *msg;
|
||||||
int pos;
|
u32 size, csum;
|
||||||
|
int pos, pad;
|
||||||
|
int ret, fd;
|
||||||
|
|
||||||
ret = load_xbc_file(xbc_path, &buf);
|
ret = load_xbc_file(xbc_path, &buf);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -346,13 +353,12 @@ static int apply_xbc(const char *path, const char *xbc_path)
|
||||||
size = strlen(buf) + 1;
|
size = strlen(buf) + 1;
|
||||||
csum = checksum((unsigned char *)buf, size);
|
csum = checksum((unsigned char *)buf, size);
|
||||||
|
|
||||||
/* Prepare xbc_path data */
|
/* Backup the bootconfig data */
|
||||||
data = malloc(size + 8);
|
data = calloc(size + BOOTCONFIG_ALIGN +
|
||||||
|
sizeof(u32) + sizeof(u32) + BOOTCONFIG_MAGIC_LEN, 1);
|
||||||
if (!data)
|
if (!data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
strcpy(data, buf);
|
memcpy(data, buf, size);
|
||||||
*(u32 *)(data + size) = size;
|
|
||||||
*(u32 *)(data + size + 4) = csum;
|
|
||||||
|
|
||||||
/* Check the data format */
|
/* Check the data format */
|
||||||
ret = xbc_init(buf, &msg, &pos);
|
ret = xbc_init(buf, &msg, &pos);
|
||||||
|
@ -383,28 +389,61 @@ static int apply_xbc(const char *path, const char *xbc_path)
|
||||||
/* Apply new one */
|
/* Apply new one */
|
||||||
fd = open(path, O_RDWR | O_APPEND);
|
fd = open(path, O_RDWR | O_APPEND);
|
||||||
if (fd < 0) {
|
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);
|
free(data);
|
||||||
return fd;
|
return ret;
|
||||||
}
|
}
|
||||||
/* TODO: Ensure the @path is initramfs/initrd image */
|
/* TODO: Ensure the @path is initramfs/initrd image */
|
||||||
ret = write(fd, data, size + 8);
|
if (fstat(fd, &stat) < 0) {
|
||||||
if (ret < 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);
|
pr_err("Failed to apply a boot config: %d\n", ret);
|
||||||
goto out;
|
if (ret >= 0)
|
||||||
}
|
goto out_rollback;
|
||||||
/* Write a magic word of the bootconfig */
|
} else
|
||||||
ret = write(fd, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN);
|
ret = 0;
|
||||||
if (ret < 0) {
|
|
||||||
pr_err("Failed to apply a boot config magic: %d\n", ret);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
ret = 0;
|
|
||||||
out:
|
out:
|
||||||
close(fd);
|
close(fd);
|
||||||
free(data);
|
free(data);
|
||||||
|
|
||||||
return ret;
|
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)
|
static int usage(void)
|
||||||
|
|
|
@ -9,6 +9,7 @@ else
|
||||||
TESTDIR=.
|
TESTDIR=.
|
||||||
fi
|
fi
|
||||||
BOOTCONF=${TESTDIR}/bootconfig
|
BOOTCONF=${TESTDIR}/bootconfig
|
||||||
|
ALIGN=4
|
||||||
|
|
||||||
INITRD=`mktemp ${TESTDIR}/initrd-XXXX`
|
INITRD=`mktemp ${TESTDIR}/initrd-XXXX`
|
||||||
TEMPCONF=`mktemp ${TESTDIR}/temp-XXXX.bconf`
|
TEMPCONF=`mktemp ${TESTDIR}/temp-XXXX.bconf`
|
||||||
|
@ -59,7 +60,10 @@ echo "Show command test"
|
||||||
xpass $BOOTCONF $INITRD
|
xpass $BOOTCONF $INITRD
|
||||||
|
|
||||||
echo "File size check"
|
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"
|
echo "Apply command repeat test"
|
||||||
xpass $BOOTCONF -a $TEMPCONF $INITRD
|
xpass $BOOTCONF -a $TEMPCONF $INITRD
|
||||||
|
|
Loading…
Reference in New Issue