Commit 74caba7f authored by John Ogness's avatar John Ogness Committed by Petr Mladek

printk: move dictionary keys to dev_printk_info

Dictionaries are only used for SUBSYSTEM and DEVICE properties. The
current implementation stores the property names each time they are
used. This requires more space than otherwise necessary. Also,
because the dictionary entries are currently considered optional,
it cannot be relied upon that they are always available, even if the
writer wanted to store them. These issues will increase should new
dictionary properties be introduced.

Rather than storing the subsystem and device properties in the
dict ring, introduce a struct dev_printk_info with separate fields
to store only the property values. Embed this struct within the
struct printk_info to provide guaranteed availability.
Signed-off-by: default avatarJohn Ogness <john.ogness@linutronix.de>
Reviewed-by: default avatarPetr Mladek <pmladek@suse.com>
Signed-off-by: default avatarPetr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/87mu1jl6ne.fsf@jogness.linutronix.de
parent cfe2790b
......@@ -172,13 +172,13 @@ end
define dump_record
set var $desc = $arg0
if ($argc > 1)
set var $prev_flags = $arg1
set var $info = $arg1
if ($argc > 2)
set var $prev_flags = $arg2
else
set var $prev_flags = 0
end
set var $info = &$desc->info
set var $prefix = 1
set var $newline = 1
......@@ -237,44 +237,36 @@ define dump_record
# handle dictionary data
set var $begin = $desc->dict_blk_lpos.begin % (1U << prb->dict_data_ring.size_bits)
set var $next = $desc->dict_blk_lpos.next % (1U << prb->dict_data_ring.size_bits)
# handle data-less record
if ($begin & 1)
set var $dict_len = 0
set var $dict = ""
else
# handle wrapping data block
if ($begin > $next)
set var $begin = 0
end
# skip over descriptor id
set var $begin = $begin + sizeof(long)
# handle truncated message
if ($next - $begin < $info->dict_len)
set var $dict_len = $next - $begin
else
set var $dict_len = $info->dict_len
set var $dict = &$info->dev_info.subsystem[0]
set var $dict_len = sizeof($info->dev_info.subsystem)
if ($dict[0] != '\0')
printf " SUBSYSTEM="
set var $idx = 0
while ($idx < $dict_len)
set var $c = $dict[$idx]
if ($c == '\0')
loop_break
else
if ($c < ' ' || $c >= 127 || $c == '\\')
printf "\\x%02x", $c
else
printf "%c", $c
end
end
set var $idx = $idx + 1
end
set var $dict = &prb->dict_data_ring.data[$begin]
printf "\n"
end
if ($dict_len > 0)
set var $dict = &$info->dev_info.device[0]
set var $dict_len = sizeof($info->dev_info.device)
if ($dict[0] != '\0')
printf " DEVICE="
set var $idx = 0
set var $line = 1
while ($idx < $dict_len)
if ($line)
printf " "
set var $line = 0
end
set var $c = $dict[$idx]
if ($c == '\0')
printf "\n"
set var $line = 1
loop_break
else
if ($c < ' ' || $c >= 127 || $c == '\\')
printf "\\x%02x", $c
......@@ -288,10 +280,10 @@ define dump_record
end
end
document dump_record
Dump a single record. The first parameter is the descriptor
sequence number, the second is optional and specifies the
previous record's flags, used for properly formatting
continued lines.
Dump a single record. The first parameter is the descriptor,
the second parameter is the info, the third parameter is
optional and specifies the previous record's flags, used for
properly formatting continued lines.
end
define dmesg
......@@ -311,12 +303,13 @@ define dmesg
while (1)
set var $desc = &prb->desc_ring.descs[$id % $desc_count]
set var $info = &prb->desc_ring.infos[$id % $desc_count]
# skip non-committed record
set var $state = 3 & ($desc->state_var.counter >> $desc_flags_shift)
if ($state == $desc_committed || $state == $desc_finalized)
dump_record $desc $prev_flags
set var $prev_flags = $desc->info.flags
dump_record $desc $info $prev_flags
set var $prev_flags = $info->flags
end
set var $id = ($id + 1) & $id_mask
......
......@@ -3815,22 +3815,21 @@ void device_shutdown(void)
*/
#ifdef CONFIG_PRINTK
static int
create_syslog_header(const struct device *dev, char *hdr, size_t hdrlen)
static void
set_dev_info(const struct device *dev, struct dev_printk_info *dev_info)
{
const char *subsys;
size_t pos = 0;
memset(dev_info, 0, sizeof(*dev_info));
if (dev->class)
subsys = dev->class->name;
else if (dev->bus)
subsys = dev->bus->name;
else
return 0;
return;
pos += snprintf(hdr + pos, hdrlen - pos, "SUBSYSTEM=%s", subsys);
if (pos >= hdrlen)
goto overflow;
strscpy(dev_info->subsystem, subsys, sizeof(dev_info->subsystem));
/*
* Add device identifier DEVICE=:
......@@ -3846,41 +3845,28 @@ create_syslog_header(const struct device *dev, char *hdr, size_t hdrlen)
c = 'b';
else
c = 'c';
pos++;
pos += snprintf(hdr + pos, hdrlen - pos,
"DEVICE=%c%u:%u",
c, MAJOR(dev->devt), MINOR(dev->devt));
snprintf(dev_info->device, sizeof(dev_info->device),
"%c%u:%u", c, MAJOR(dev->devt), MINOR(dev->devt));
} else if (strcmp(subsys, "net") == 0) {
struct net_device *net = to_net_dev(dev);
pos++;
pos += snprintf(hdr + pos, hdrlen - pos,
"DEVICE=n%u", net->ifindex);
snprintf(dev_info->device, sizeof(dev_info->device),
"n%u", net->ifindex);
} else {
pos++;
pos += snprintf(hdr + pos, hdrlen - pos,
"DEVICE=+%s:%s", subsys, dev_name(dev));
snprintf(dev_info->device, sizeof(dev_info->device),
"+%s:%s", subsys, dev_name(dev));
}
if (pos >= hdrlen)
goto overflow;
return pos;
overflow:
dev_WARN(dev, "device/subsystem name too long");
return 0;
}
int dev_vprintk_emit(int level, const struct device *dev,
const char *fmt, va_list args)
{
char hdr[128];
size_t hdrlen;
struct dev_printk_info dev_info;
hdrlen = create_syslog_header(dev, hdr, sizeof(hdr));
set_dev_info(dev, &dev_info);
return vprintk_emit(0, level, hdrlen ? hdr : NULL, hdrlen, fmt, args);
return vprintk_emit(0, level, &dev_info, fmt, args);
}
EXPORT_SYMBOL(dev_vprintk_emit);
......
......@@ -21,6 +21,14 @@
struct device;
#define PRINTK_INFO_SUBSYSTEM_LEN 16
#define PRINTK_INFO_DEVICE_LEN 48
struct dev_printk_info {
char subsystem[PRINTK_INFO_SUBSYSTEM_LEN];
char device[PRINTK_INFO_DEVICE_LEN];
};
#ifdef CONFIG_PRINTK
__printf(3, 0) __cold
......
......@@ -158,10 +158,12 @@ static inline void printk_nmi_direct_enter(void) { }
static inline void printk_nmi_direct_exit(void) { }
#endif /* PRINTK_NMI */
struct dev_printk_info;
#ifdef CONFIG_PRINTK
asmlinkage __printf(5, 0)
asmlinkage __printf(4, 0)
int vprintk_emit(int facility, int level,
const char *dict, size_t dictlen,
const struct dev_printk_info *dev_info,
const char *fmt, va_list args);
asmlinkage __printf(1, 0)
......
......@@ -14,9 +14,9 @@
extern raw_spinlock_t logbuf_lock;
__printf(5, 0)
__printf(4, 0)
int vprintk_store(int facility, int level,
const char *dict, size_t dictlen,
const struct dev_printk_info *dev_info,
const char *fmt, va_list args);
__printf(1, 0) int vprintk_default(const char *fmt, va_list args);
......
This diff is collapsed.
......@@ -4,6 +4,7 @@
#define _KERNEL_PRINTK_RINGBUFFER_H
#include <linux/atomic.h>
#include <linux/dev_printk.h>
/*
* Meta information about each stored message.
......@@ -21,6 +22,8 @@ struct printk_info {
u8 flags:5; /* internal record flags */
u8 level:3; /* syslog level */
u32 caller_id; /* thread id or processor id */
struct dev_printk_info dev_info;
};
/*
......
......@@ -375,7 +375,7 @@ __printf(1, 0) int vprintk_func(const char *fmt, va_list args)
raw_spin_trylock(&logbuf_lock)) {
int len;
len = vprintk_store(0, LOGLEVEL_DEFAULT, NULL, 0, fmt, args);
len = vprintk_store(0, LOGLEVEL_DEFAULT, NULL, fmt, args);
raw_spin_unlock(&logbuf_lock);
defer_console_output();
return len;
......
......@@ -52,6 +52,12 @@ class LxDmesg(gdb.Command):
addr = utils.read_ulong(desc_ring, off)
descs = utils.read_memoryview(inf, addr, desc_sz * desc_ring_count).tobytes()
# read in info array
info_sz = printk_info_type.get_type().sizeof
off = prb_desc_ring_type.get_type()['infos'].bitpos // 8
addr = utils.read_ulong(desc_ring, off)
infos = utils.read_memoryview(inf, addr, info_sz * desc_ring_count).tobytes()
# read in text data ring structure
off = printk_ringbuffer_type.get_type()['text_data_ring'].bitpos // 8
addr = prb_addr + off
......@@ -73,9 +79,8 @@ class LxDmesg(gdb.Command):
begin_off = off + (prb_data_blk_lpos_type.get_type()['begin'].bitpos // 8)
next_off = off + (prb_data_blk_lpos_type.get_type()['next'].bitpos // 8)
off = prb_desc_type.get_type()['info'].bitpos // 8
ts_off = off + printk_info_type.get_type()['ts_nsec'].bitpos // 8
len_off = off + printk_info_type.get_type()['text_len'].bitpos // 8
ts_off = printk_info_type.get_type()['ts_nsec'].bitpos // 8
len_off = printk_info_type.get_type()['text_len'].bitpos // 8
# definitions from kernel/printk/printk_ringbuffer.h
desc_committed = 1
......@@ -95,6 +100,7 @@ class LxDmesg(gdb.Command):
while True:
ind = did % desc_ring_count
desc_off = desc_sz * ind
info_off = info_sz * ind
# skip non-committed record
state = 3 & (utils.read_u64(descs, desc_off + sv_off +
......@@ -119,7 +125,7 @@ class LxDmesg(gdb.Command):
# skip over descriptor id
text_start = begin + utils.get_long_type().sizeof
text_len = utils.read_u16(descs, desc_off + len_off)
text_len = utils.read_u16(infos, info_off + len_off)
# handle truncated message
if end - text_start < text_len:
......@@ -128,7 +134,7 @@ class LxDmesg(gdb.Command):
text = text_data[text_start:text_start + text_len].decode(
encoding='utf8', errors='replace')
time_stamp = utils.read_u64(descs, desc_off + ts_off)
time_stamp = utils.read_u64(infos, info_off + ts_off)
for line in text.splitlines():
msg = u"[{time:12.6f}] {line}\n".format(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment