Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
392143c9
Commit
392143c9
authored
Feb 21, 2023
by
Petr Mladek
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'rework/buffers-cleanup' into for-linus
parents
0c2baf65
d551afc2
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
297 additions
and
158 deletions
+297
-158
include/linux/console.h
include/linux/console.h
+73
-27
include/linux/printk.h
include/linux/printk.h
+0
-2
kernel/printk/internal.h
kernel/printk/internal.h
+45
-0
kernel/printk/printk.c
kernel/printk/printk.c
+179
-129
No files found.
include/linux/console.h
View file @
392143c9
...
...
@@ -15,6 +15,7 @@
#define _LINUX_CONSOLE_H_ 1
#include <linux/atomic.h>
#include <linux/bits.h>
#include <linux/rculist.h>
#include <linux/types.h>
...
...
@@ -125,37 +126,82 @@ static inline int con_debug_leave(void)
/*
* The interface for a console, or any other device that wants to capture
* console messages (printer driver?)
*
* If a console driver is marked CON_BOOT then it will be auto-unregistered
* when the first real console is registered. This is for early-printk drivers.
*/
#define CON_PRINTBUFFER (1)
#define CON_CONSDEV (2)
/* Preferred console, /dev/console */
#define CON_ENABLED (4)
#define CON_BOOT (8)
#define CON_ANYTIME (16)
/* Safe to call when cpu is offline */
#define CON_BRL (32)
/* Used for a braille device */
#define CON_EXTENDED (64)
/* Use the extended output format a la /dev/kmsg */
/**
* cons_flags - General console flags
* @CON_PRINTBUFFER: Used by newly registered consoles to avoid duplicate
* output of messages that were already shown by boot
* consoles or read by userspace via syslog() syscall.
* @CON_CONSDEV: Indicates that the console driver is backing
* /dev/console.
* @CON_ENABLED: Indicates if a console is allowed to print records. If
* false, the console also will not advance to later
* records.
* @CON_BOOT: Marks the console driver as early console driver which
* is used during boot before the real driver becomes
* available. It will be automatically unregistered
* when the real console driver is registered unless
* "keep_bootcon" parameter is used.
* @CON_ANYTIME: A misnomed historical flag which tells the core code
* that the legacy @console::write callback can be invoked
* on a CPU which is marked OFFLINE. That is misleading as
* it suggests that there is no contextual limit for
* invoking the callback. The original motivation was
* readiness of the per-CPU areas.
* @CON_BRL: Indicates a braille device which is exempt from
* receiving the printk spam for obvious reasons.
* @CON_EXTENDED: The console supports the extended output format of
* /dev/kmesg which requires a larger output buffer.
*/
enum
cons_flags
{
CON_PRINTBUFFER
=
BIT
(
0
),
CON_CONSDEV
=
BIT
(
1
),
CON_ENABLED
=
BIT
(
2
),
CON_BOOT
=
BIT
(
3
),
CON_ANYTIME
=
BIT
(
4
),
CON_BRL
=
BIT
(
5
),
CON_EXTENDED
=
BIT
(
6
),
};
/**
* struct console - The console descriptor structure
* @name: The name of the console driver
* @write: Write callback to output messages (Optional)
* @read: Read callback for console input (Optional)
* @device: The underlying TTY device driver (Optional)
* @unblank: Callback to unblank the console (Optional)
* @setup: Callback for initializing the console (Optional)
* @exit: Callback for teardown of the console (Optional)
* @match: Callback for matching a console (Optional)
* @flags: Console flags. See enum cons_flags
* @index: Console index, e.g. port number
* @cflag: TTY control mode flags
* @ispeed: TTY input speed
* @ospeed: TTY output speed
* @seq: Sequence number of the next ringbuffer record to print
* @dropped: Number of unreported dropped ringbuffer records
* @data: Driver private data
* @node: hlist node for the console list
*/
struct
console
{
char
name
[
16
];
void
(
*
write
)(
struct
console
*
,
const
char
*
,
unsigned
);
int
(
*
read
)(
struct
console
*
,
char
*
,
unsigned
);
struct
tty_driver
*
(
*
device
)(
struct
console
*
,
int
*
);
void
(
*
unblank
)(
void
);
int
(
*
setup
)(
struct
console
*
,
char
*
);
int
(
*
exit
)(
struct
console
*
);
int
(
*
match
)(
struct
console
*
,
char
*
name
,
int
idx
,
char
*
options
);
short
flags
;
short
index
;
int
cflag
;
uint
ispeed
;
uint
ospeed
;
u64
seq
;
unsigned
long
dropped
;
void
*
data
;
struct
hlist_node
node
;
char
name
[
16
];
void
(
*
write
)(
struct
console
*
co
,
const
char
*
s
,
unsigned
int
count
);
int
(
*
read
)(
struct
console
*
co
,
char
*
s
,
unsigned
int
count
);
struct
tty_driver
*
(
*
device
)(
struct
console
*
co
,
int
*
index
);
void
(
*
unblank
)(
void
);
int
(
*
setup
)(
struct
console
*
co
,
char
*
options
);
int
(
*
exit
)(
struct
console
*
co
);
int
(
*
match
)(
struct
console
*
co
,
char
*
name
,
int
idx
,
char
*
options
);
short
flags
;
short
index
;
int
cflag
;
uint
ispeed
;
uint
ospeed
;
u64
seq
;
unsigned
long
dropped
;
void
*
data
;
struct
hlist_node
node
;
};
#ifdef CONFIG_LOCKDEP
...
...
include/linux/printk.h
View file @
392143c9
...
...
@@ -44,8 +44,6 @@ static inline const char *printk_skip_headers(const char *buffer)
return
buffer
;
}
#define CONSOLE_EXT_LOG_MAX 8192
/* printk's without a loglevel use this.. */
#define MESSAGE_LOGLEVEL_DEFAULT CONFIG_MESSAGE_LOGLEVEL_DEFAULT
...
...
kernel/printk/internal.h
View file @
392143c9
...
...
@@ -14,6 +14,21 @@ int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write,
#ifdef CONFIG_PRINTK
#ifdef CONFIG_PRINTK_CALLER
#define PRINTK_PREFIX_MAX 48
#else
#define PRINTK_PREFIX_MAX 32
#endif
/*
* the maximum size of a formatted record (i.e. with prefix added
* per line and dropped messages or in extended message format)
*/
#define PRINTK_MESSAGE_MAX 2048
/* the maximum size allowed to be reserved for a record */
#define PRINTKRB_RECORD_MAX 1024
/* Flags for a single printk record. */
enum
printk_info_flags
{
LOG_NEWLINE
=
2
,
/* text ended with a newline */
...
...
@@ -48,6 +63,10 @@ u16 printk_parse_prefix(const char *text, int *level,
enum
printk_info_flags
*
flags
);
#else
#define PRINTK_PREFIX_MAX 0
#define PRINTK_MESSAGE_MAX 0
#define PRINTKRB_RECORD_MAX 0
/*
* In !PRINTK builds we still export console_sem
* semaphore and some of console functions (console_unlock()/etc.), so
...
...
@@ -58,3 +77,29 @@ u16 printk_parse_prefix(const char *text, int *level,
static
inline
bool
printk_percpu_data_ready
(
void
)
{
return
false
;
}
#endif
/* CONFIG_PRINTK */
/**
* struct printk_buffers - Buffers to read/format/output printk messages.
* @outbuf: After formatting, contains text to output.
* @scratchbuf: Used as temporary ringbuffer reading and string-print space.
*/
struct
printk_buffers
{
char
outbuf
[
PRINTK_MESSAGE_MAX
];
char
scratchbuf
[
PRINTKRB_RECORD_MAX
];
};
/**
* struct printk_message - Container for a prepared printk message.
* @pbufs: printk buffers used to prepare the message.
* @outbuf_len: The length of prepared text in @pbufs->outbuf to output. This
* does not count the terminator. A value of 0 means there is
* nothing to output and this record should be skipped.
* @seq: The sequence number of the record used for @pbufs->outbuf.
* @dropped: The number of dropped records from reading @seq.
*/
struct
printk_message
{
struct
printk_buffers
*
pbufs
;
unsigned
int
outbuf_len
;
u64
seq
;
unsigned
long
dropped
;
};
kernel/printk/printk.c
View file @
392143c9
...
...
@@ -465,21 +465,6 @@ static struct latched_seq clear_seq = {
.
val
[
1
]
=
0
,
};
#ifdef CONFIG_PRINTK_CALLER
#define PREFIX_MAX 48
#else
#define PREFIX_MAX 32
#endif
/* the maximum size of a formatted record (i.e. with prefix added per line) */
#define CONSOLE_LOG_MAX 1024
/* the maximum size for a dropped text message */
#define DROPPED_TEXT_MAX 64
/* the maximum size allowed to be reserved for a record */
#define LOG_LINE_MAX (CONSOLE_LOG_MAX - PREFIX_MAX)
#define LOG_LEVEL(v) ((v) & 0x07)
#define LOG_FACILITY(v) ((v) >> 3 & 0xff)
...
...
@@ -710,16 +695,15 @@ static ssize_t msg_print_ext_body(char *buf, size_t size,
return
len
;
}
static
bool
printk_get_next_message
(
struct
printk_message
*
pmsg
,
u64
seq
,
bool
is_extended
,
bool
may_supress
);
/* /dev/kmsg - userspace message inject/listen interface */
struct
devkmsg_user
{
atomic64_t
seq
;
struct
ratelimit_state
rs
;
struct
mutex
lock
;
char
buf
[
CONSOLE_EXT_LOG_MAX
];
struct
printk_info
info
;
char
text_buf
[
CONSOLE_EXT_LOG_MAX
];
struct
printk_record
record
;
struct
printk_buffers
pbufs
;
};
static
__printf
(
3
,
4
)
__cold
...
...
@@ -745,7 +729,7 @@ static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from)
size_t
len
=
iov_iter_count
(
from
);
ssize_t
ret
=
len
;
if
(
!
user
||
len
>
LOG_LINE
_MAX
)
if
(
!
user
||
len
>
PRINTKRB_RECORD
_MAX
)
return
-
EINVAL
;
/* Ignore when user logging is disabled. */
...
...
@@ -801,8 +785,10 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
size_t
count
,
loff_t
*
ppos
)
{
struct
devkmsg_user
*
user
=
file
->
private_data
;
struct
printk_record
*
r
=
&
user
->
record
;
size_t
len
;
char
*
outbuf
=
&
user
->
pbufs
.
outbuf
[
0
];
struct
printk_message
pmsg
=
{
.
pbufs
=
&
user
->
pbufs
,
};
ssize_t
ret
;
if
(
!
user
)
...
...
@@ -812,7 +798,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
if
(
ret
)
return
ret
;
if
(
!
pr
b_read_valid
(
prb
,
atomic64_read
(
&
user
->
seq
),
r
))
{
if
(
!
pr
intk_get_next_message
(
&
pmsg
,
atomic64_read
(
&
user
->
seq
),
true
,
false
))
{
if
(
file
->
f_flags
&
O_NONBLOCK
)
{
ret
=
-
EAGAIN
;
goto
out
;
...
...
@@ -829,36 +815,31 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
* This pairs with __wake_up_klogd:A.
*/
ret
=
wait_event_interruptible
(
log_wait
,
pr
b_read_valid
(
prb
,
atomic64_read
(
&
user
->
seq
),
r
));
/* LMM(devkmsg_read:A) */
pr
intk_get_next_message
(
&
pmsg
,
atomic64_read
(
&
user
->
seq
),
true
,
false
));
/* LMM(devkmsg_read:A) */
if
(
ret
)
goto
out
;
}
if
(
r
->
info
->
seq
!=
atomic64_read
(
&
user
->
seq
)
)
{
if
(
pmsg
.
dropped
)
{
/* our last seen message is gone, return error and reset */
atomic64_set
(
&
user
->
seq
,
r
->
info
->
seq
);
atomic64_set
(
&
user
->
seq
,
pmsg
.
seq
);
ret
=
-
EPIPE
;
goto
out
;
}
len
=
info_print_ext_header
(
user
->
buf
,
sizeof
(
user
->
buf
),
r
->
info
);
len
+=
msg_print_ext_body
(
user
->
buf
+
len
,
sizeof
(
user
->
buf
)
-
len
,
&
r
->
text_buf
[
0
],
r
->
info
->
text_len
,
&
r
->
info
->
dev_info
);
atomic64_set
(
&
user
->
seq
,
r
->
info
->
seq
+
1
);
atomic64_set
(
&
user
->
seq
,
pmsg
.
seq
+
1
);
if
(
len
>
count
)
{
if
(
pmsg
.
outbuf_
len
>
count
)
{
ret
=
-
EINVAL
;
goto
out
;
}
if
(
copy_to_user
(
buf
,
user
->
buf
,
len
))
{
if
(
copy_to_user
(
buf
,
outbuf
,
pmsg
.
outbuf_
len
))
{
ret
=
-
EFAULT
;
goto
out
;
}
ret
=
len
;
ret
=
pmsg
.
outbuf_
len
;
out:
mutex_unlock
(
&
user
->
lock
);
return
ret
;
...
...
@@ -952,9 +933,6 @@ static int devkmsg_open(struct inode *inode, struct file *file)
mutex_init
(
&
user
->
lock
);
prb_rec_init_rd
(
&
user
->
record
,
&
user
->
info
,
&
user
->
text_buf
[
0
],
sizeof
(
user
->
text_buf
));
atomic64_set
(
&
user
->
seq
,
prb_first_valid_seq
(
prb
));
file
->
private_data
=
user
;
...
...
@@ -1149,7 +1127,7 @@ static unsigned int __init add_to_rb(struct printk_ringbuffer *rb,
return
prb_record_text_space
(
&
e
);
}
static
char
setup_text_buf
[
LOG_LINE
_MAX
]
__initdata
;
static
char
setup_text_buf
[
PRINTKRB_RECORD
_MAX
]
__initdata
;
void
__init
setup_log_buf
(
int
early
)
{
...
...
@@ -1415,7 +1393,7 @@ static size_t record_print_text(struct printk_record *r, bool syslog,
size_t
text_len
=
r
->
info
->
text_len
;
size_t
buf_size
=
r
->
text_buf_size
;
char
*
text
=
r
->
text_buf
;
char
prefix
[
PREFIX_MAX
];
char
prefix
[
PR
INTK_PR
EFIX_MAX
];
bool
truncated
=
false
;
size_t
prefix_len
;
size_t
line_len
;
...
...
@@ -1514,7 +1492,7 @@ static size_t get_record_print_text_size(struct printk_info *info,
unsigned
int
line_count
,
bool
syslog
,
bool
time
)
{
char
prefix
[
PREFIX_MAX
];
char
prefix
[
PR
INTK_PR
EFIX_MAX
];
size_t
prefix_len
;
prefix_len
=
info_print_prefix
(
info
,
syslog
,
time
,
prefix
);
...
...
@@ -1580,11 +1558,11 @@ static int syslog_print(char __user *buf, int size)
int
len
=
0
;
u64
seq
;
text
=
kmalloc
(
CONSOLE_LOG
_MAX
,
GFP_KERNEL
);
text
=
kmalloc
(
PRINTK_MESSAGE
_MAX
,
GFP_KERNEL
);
if
(
!
text
)
return
-
ENOMEM
;
prb_rec_init_rd
(
&
r
,
&
info
,
text
,
CONSOLE_LOG
_MAX
);
prb_rec_init_rd
(
&
r
,
&
info
,
text
,
PRINTK_MESSAGE
_MAX
);
mutex_lock
(
&
syslog_lock
);
...
...
@@ -1685,7 +1663,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
u64
seq
;
bool
time
;
text
=
kmalloc
(
CONSOLE_LOG
_MAX
,
GFP_KERNEL
);
text
=
kmalloc
(
PRINTK_MESSAGE
_MAX
,
GFP_KERNEL
);
if
(
!
text
)
return
-
ENOMEM
;
...
...
@@ -1697,7 +1675,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
seq
=
find_first_fitting_seq
(
latched_seq_read_nolock
(
&
clear_seq
),
-
1
,
size
,
true
,
time
);
prb_rec_init_rd
(
&
r
,
&
info
,
text
,
CONSOLE_LOG
_MAX
);
prb_rec_init_rd
(
&
r
,
&
info
,
text
,
PRINTK_MESSAGE
_MAX
);
len
=
0
;
prb_for_each_record
(
seq
,
prb
,
seq
,
&
r
)
{
...
...
@@ -2010,27 +1988,6 @@ static int console_trylock_spinning(void)
return
1
;
}
/*
* Call the specified console driver, asking it to write out the specified
* text and length. If @dropped_text is non-NULL and any records have been
* dropped, a dropped message will be written out first.
*/
static
void
call_console_driver
(
struct
console
*
con
,
const
char
*
text
,
size_t
len
,
char
*
dropped_text
)
{
size_t
dropped_len
;
if
(
con
->
dropped
&&
dropped_text
)
{
dropped_len
=
snprintf
(
dropped_text
,
DROPPED_TEXT_MAX
,
"** %lu printk messages dropped **
\n
"
,
con
->
dropped
);
con
->
dropped
=
0
;
con
->
write
(
con
,
dropped_text
,
dropped_len
);
}
con
->
write
(
con
,
text
,
len
);
}
/*
* Recursion is tracked separately on each CPU. If NMIs are supported, an
* additional NMI context per CPU is also separately tracked. Until per-CPU
...
...
@@ -2241,8 +2198,8 @@ int vprintk_store(int facility, int level,
reserve_size
=
vsnprintf
(
&
prefix_buf
[
0
],
sizeof
(
prefix_buf
),
fmt
,
args2
)
+
1
;
va_end
(
args2
);
if
(
reserve_size
>
LOG_LINE
_MAX
)
reserve_size
=
LOG_LINE
_MAX
;
if
(
reserve_size
>
PRINTKRB_RECORD
_MAX
)
reserve_size
=
PRINTKRB_RECORD
_MAX
;
/* Extract log level or control flags. */
if
(
facility
==
0
)
...
...
@@ -2256,7 +2213,7 @@ int vprintk_store(int facility, int level,
if
(
flags
&
LOG_CONT
)
{
prb_rec_init_wr
(
&
r
,
reserve_size
);
if
(
prb_reserve_in_last
(
&
e
,
prb
,
&
r
,
caller_id
,
LOG_LINE
_MAX
))
{
if
(
prb_reserve_in_last
(
&
e
,
prb
,
&
r
,
caller_id
,
PRINTKRB_RECORD
_MAX
))
{
text_len
=
printk_sprint
(
&
r
.
text_buf
[
r
.
info
->
text_len
],
reserve_size
,
facility
,
&
flags
,
fmt
,
args
);
r
.
info
->
text_len
+=
text_len
;
...
...
@@ -2387,8 +2344,6 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
#else
/* CONFIG_PRINTK */
#define CONSOLE_LOG_MAX 0
#define DROPPED_TEXT_MAX 0
#define printk_time false
#define prb_read_valid(rb, seq, r) false
...
...
@@ -2412,10 +2367,6 @@ static ssize_t msg_print_ext_body(char *buf, size_t size,
struct
dev_printk_info
*
dev_info
)
{
return
0
;
}
static
void
console_lock_spinning_enable
(
void
)
{
}
static
int
console_lock_spinning_disable_and_check
(
int
cookie
)
{
return
0
;
}
static
void
call_console_driver
(
struct
console
*
con
,
const
char
*
text
,
size_t
len
,
char
*
dropped_text
)
{
}
static
bool
suppress_message_printing
(
int
level
)
{
return
false
;
}
static
bool
pr_flush
(
int
timeout_ms
,
bool
reset_on_progress
)
{
return
true
;
}
static
bool
__pr_flush
(
struct
console
*
con
,
int
timeout_ms
,
bool
reset_on_progress
)
{
return
true
;
}
...
...
@@ -2742,16 +2693,136 @@ static void __console_unlock(void)
}
/*
* Print one record for the given console. The record printed is whatever
* record is the next available record for the given console.
* Prepend the message in @pmsg->pbufs->outbuf with a "dropped message". This
* is achieved by shifting the existing message over and inserting the dropped
* message.
*
* @pmsg is the printk message to prepend.
*
* @
text is a buffer of size CONSOLE_LOG_MAX
.
* @
dropped is the dropped count to report in the dropped message
.
*
* If
extended messages should be printed, @ext_text is a buffer of size
*
CONSOLE_EXT_LOG_MAX. Otherwise @ext_text must be NULL
.
* If
the message text in @pmsg->pbufs->outbuf does not have enough space for
*
the dropped message, the message text will be sufficiently truncated
.
*
* If dropped messages should be printed, @dropped_text is a buffer of size
* DROPPED_TEXT_MAX. Otherwise @dropped_text must be NULL.
* If @pmsg->pbufs->outbuf is modified, @pmsg->outbuf_len is updated.
*/
#ifdef CONFIG_PRINTK
static
void
console_prepend_dropped
(
struct
printk_message
*
pmsg
,
unsigned
long
dropped
)
{
struct
printk_buffers
*
pbufs
=
pmsg
->
pbufs
;
const
size_t
scratchbuf_sz
=
sizeof
(
pbufs
->
scratchbuf
);
const
size_t
outbuf_sz
=
sizeof
(
pbufs
->
outbuf
);
char
*
scratchbuf
=
&
pbufs
->
scratchbuf
[
0
];
char
*
outbuf
=
&
pbufs
->
outbuf
[
0
];
size_t
len
;
len
=
scnprintf
(
scratchbuf
,
scratchbuf_sz
,
"** %lu printk messages dropped **
\n
"
,
dropped
);
/*
* Make sure outbuf is sufficiently large before prepending.
* Keep at least the prefix when the message must be truncated.
* It is a rather theoretical problem when someone tries to
* use a minimalist buffer.
*/
if
(
WARN_ON_ONCE
(
len
+
PRINTK_PREFIX_MAX
>=
outbuf_sz
))
return
;
if
(
pmsg
->
outbuf_len
+
len
>=
outbuf_sz
)
{
/* Truncate the message, but keep it terminated. */
pmsg
->
outbuf_len
=
outbuf_sz
-
(
len
+
1
);
outbuf
[
pmsg
->
outbuf_len
]
=
0
;
}
memmove
(
outbuf
+
len
,
outbuf
,
pmsg
->
outbuf_len
+
1
);
memcpy
(
outbuf
,
scratchbuf
,
len
);
pmsg
->
outbuf_len
+=
len
;
}
#else
#define console_prepend_dropped(pmsg, dropped)
#endif
/* CONFIG_PRINTK */
/*
* Read and format the specified record (or a later record if the specified
* record is not available).
*
* @pmsg will contain the formatted result. @pmsg->pbufs must point to a
* struct printk_buffers.
*
* @seq is the record to read and format. If it is not available, the next
* valid record is read.
*
* @is_extended specifies if the message should be formatted for extended
* console output.
*
* @may_supress specifies if records may be skipped based on loglevel.
*
* Returns false if no record is available. Otherwise true and all fields
* of @pmsg are valid. (See the documentation of struct printk_message
* for information about the @pmsg fields.)
*/
static
bool
printk_get_next_message
(
struct
printk_message
*
pmsg
,
u64
seq
,
bool
is_extended
,
bool
may_suppress
)
{
static
int
panic_console_dropped
;
struct
printk_buffers
*
pbufs
=
pmsg
->
pbufs
;
const
size_t
scratchbuf_sz
=
sizeof
(
pbufs
->
scratchbuf
);
const
size_t
outbuf_sz
=
sizeof
(
pbufs
->
outbuf
);
char
*
scratchbuf
=
&
pbufs
->
scratchbuf
[
0
];
char
*
outbuf
=
&
pbufs
->
outbuf
[
0
];
struct
printk_info
info
;
struct
printk_record
r
;
size_t
len
=
0
;
/*
* Formatting extended messages requires a separate buffer, so use the
* scratch buffer to read in the ringbuffer text.
*
* Formatting normal messages is done in-place, so read the ringbuffer
* text directly into the output buffer.
*/
if
(
is_extended
)
prb_rec_init_rd
(
&
r
,
&
info
,
scratchbuf
,
scratchbuf_sz
);
else
prb_rec_init_rd
(
&
r
,
&
info
,
outbuf
,
outbuf_sz
);
if
(
!
prb_read_valid
(
prb
,
seq
,
&
r
))
return
false
;
pmsg
->
seq
=
r
.
info
->
seq
;
pmsg
->
dropped
=
r
.
info
->
seq
-
seq
;
/*
* Check for dropped messages in panic here so that printk
* suppression can occur as early as possible if necessary.
*/
if
(
pmsg
->
dropped
&&
panic_in_progress
()
&&
panic_console_dropped
++
>
10
)
{
suppress_panic_printk
=
1
;
pr_warn_once
(
"Too many dropped messages. Suppress messages on non-panic CPUs to prevent livelock.
\n
"
);
}
/* Skip record that has level above the console loglevel. */
if
(
may_suppress
&&
suppress_message_printing
(
r
.
info
->
level
))
goto
out
;
if
(
is_extended
)
{
len
=
info_print_ext_header
(
outbuf
,
outbuf_sz
,
r
.
info
);
len
+=
msg_print_ext_body
(
outbuf
+
len
,
outbuf_sz
-
len
,
&
r
.
text_buf
[
0
],
r
.
info
->
text_len
,
&
r
.
info
->
dev_info
);
}
else
{
len
=
record_print_text
(
&
r
,
console_msg_format
&
MSG_FORMAT_SYSLOG
,
printk_time
);
}
out:
pmsg
->
outbuf_len
=
len
;
return
true
;
}
/*
* Print one record for the given console. The record printed is whatever
* record is the next available record for the given console.
*
* @handover will be set to true if a printk waiter has taken over the
* console_lock, in which case the caller is no longer holding both the
...
...
@@ -2764,46 +2835,33 @@ static void __console_unlock(void)
*
* Requires the console_lock and the SRCU read lock.
*/
static
bool
console_emit_next_record
(
struct
console
*
con
,
char
*
text
,
char
*
ext_text
,
char
*
dropped_text
,
bool
*
handover
,
int
cookie
)
static
bool
console_emit_next_record
(
struct
console
*
con
,
bool
*
handover
,
int
cookie
)
{
static
int
panic_console_dropped
;
struct
printk_info
info
;
struct
printk_record
r
;
unsigned
long
flags
;
char
*
write_text
;
size_t
len
;
static
struct
printk_buffers
pbufs
;
prb_rec_init_rd
(
&
r
,
&
info
,
text
,
CONSOLE_LOG_MAX
);
bool
is_extended
=
console_srcu_read_flags
(
con
)
&
CON_EXTENDED
;
char
*
outbuf
=
&
pbufs
.
outbuf
[
0
];
struct
printk_message
pmsg
=
{
.
pbufs
=
&
pbufs
,
};
unsigned
long
flags
;
*
handover
=
false
;
if
(
!
pr
b_read_valid
(
prb
,
con
->
seq
,
&
r
))
if
(
!
pr
intk_get_next_message
(
&
pmsg
,
con
->
seq
,
is_extended
,
true
))
return
false
;
if
(
con
->
seq
!=
r
.
info
->
seq
)
{
con
->
dropped
+=
r
.
info
->
seq
-
con
->
seq
;
con
->
seq
=
r
.
info
->
seq
;
if
(
panic_in_progress
()
&&
panic_console_dropped
++
>
10
)
{
suppress_panic_printk
=
1
;
pr_warn_once
(
"Too many dropped messages. Suppress messages on non-panic CPUs to prevent livelock.
\n
"
);
}
}
con
->
dropped
+=
pmsg
.
dropped
;
/* Skip
record that has level above the console loglevel
. */
if
(
suppress_message_printing
(
r
.
info
->
level
)
)
{
con
->
seq
++
;
/* Skip
messages of formatted length 0
. */
if
(
pmsg
.
outbuf_len
==
0
)
{
con
->
seq
=
pmsg
.
seq
+
1
;
goto
skip
;
}
if
(
ext_text
)
{
write_text
=
ext_text
;
len
=
info_print_ext_header
(
ext_text
,
CONSOLE_EXT_LOG_MAX
,
r
.
info
);
len
+=
msg_print_ext_body
(
ext_text
+
len
,
CONSOLE_EXT_LOG_MAX
-
len
,
&
r
.
text_buf
[
0
],
r
.
info
->
text_len
,
&
r
.
info
->
dev_info
);
}
else
{
write_text
=
text
;
len
=
record_print_text
(
&
r
,
console_msg_format
&
MSG_FORMAT_SYSLOG
,
printk_time
);
if
(
con
->
dropped
&&
!
is_extended
)
{
console_prepend_dropped
(
&
pmsg
,
con
->
dropped
);
con
->
dropped
=
0
;
}
/*
...
...
@@ -2819,11 +2877,15 @@ static bool console_emit_next_record(struct console *con, char *text, char *ext_
printk_safe_enter_irqsave
(
flags
);
console_lock_spinning_enable
();
stop_critical_timings
();
/* don't trace print latency */
call_console_driver
(
con
,
write_text
,
len
,
dropped_text
);
/* Do not trace print latency. */
stop_critical_timings
();
/* Write everything out to the hardware. */
con
->
write
(
con
,
outbuf
,
pmsg
.
outbuf_len
);
start_critical_timings
();
con
->
seq
++
;
con
->
seq
=
pmsg
.
seq
+
1
;
*
handover
=
console_lock_spinning_disable_and_check
(
cookie
);
printk_safe_exit_irqrestore
(
flags
);
...
...
@@ -2856,9 +2918,6 @@ static bool console_emit_next_record(struct console *con, char *text, char *ext_
*/
static
bool
console_flush_all
(
bool
do_cond_resched
,
u64
*
next_seq
,
bool
*
handover
)
{
static
char
dropped_text
[
DROPPED_TEXT_MAX
];
static
char
ext_text
[
CONSOLE_EXT_LOG_MAX
];
static
char
text
[
CONSOLE_LOG_MAX
];
bool
any_usable
=
false
;
struct
console
*
con
;
bool
any_progress
;
...
...
@@ -2878,16 +2937,7 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
continue
;
any_usable
=
true
;
if
(
console_srcu_read_flags
(
con
)
&
CON_EXTENDED
)
{
/* Extended consoles do not print "dropped messages". */
progress
=
console_emit_next_record
(
con
,
&
text
[
0
],
&
ext_text
[
0
],
NULL
,
handover
,
cookie
);
}
else
{
progress
=
console_emit_next_record
(
con
,
&
text
[
0
],
NULL
,
&
dropped_text
[
0
],
handover
,
cookie
);
}
progress
=
console_emit_next_record
(
con
,
handover
,
cookie
);
/*
* If a handover has occurred, the SRCU read lock
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment