Skip to content

Commit

Permalink
printk: move dictionary keys to dev_printk_info
Browse files Browse the repository at this point in the history
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: John Ogness <[email protected]>
Reviewed-by: Petr Mladek <[email protected]>
Signed-off-by: Petr Mladek <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
  • Loading branch information
jogness authored and pmladek committed Sep 22, 2020
1 parent cfe2790 commit 74caba7
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 160 deletions.
73 changes: 33 additions & 40 deletions Documentation/admin-guide/kdump/gdbmacros.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
46 changes: 16 additions & 30 deletions drivers/base/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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=:
Expand All @@ -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);

Expand Down
8 changes: 8 additions & 0 deletions include/linux/dev_printk.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions include/linux/printk.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions kernel/printk/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading

0 comments on commit 74caba7

Please sign in to comment.