Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
kernel_linux
提交
bb4f552a
K
kernel_linux
项目概览
OpenHarmony
/
kernel_linux
上一次同步 4 年多
通知
15
Star
8
Fork
2
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
kernel_linux
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
bb4f552a
编写于
1月 22, 2018
作者:
P
Petr Mladek
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-4.16-console-waiter-logic' into for-4.16
上级
51ccbb0a
fd5f7cde
变更
1
显示空白变更内容
内联
并排
Showing
1 changed file
with
166 addition
and
15 deletion
+166
-15
kernel/printk/printk.c
kernel/printk/printk.c
+166
-15
未找到文件。
kernel/printk/printk.c
浏览文件 @
bb4f552a
...
@@ -1547,6 +1547,146 @@ SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
...
@@ -1547,6 +1547,146 @@ SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
return
do_syslog
(
type
,
buf
,
len
,
SYSLOG_FROM_READER
);
return
do_syslog
(
type
,
buf
,
len
,
SYSLOG_FROM_READER
);
}
}
/*
* Special console_lock variants that help to reduce the risk of soft-lockups.
* They allow to pass console_lock to another printk() call using a busy wait.
*/
#ifdef CONFIG_LOCKDEP
static
struct
lockdep_map
console_owner_dep_map
=
{
.
name
=
"console_owner"
};
#endif
static
DEFINE_RAW_SPINLOCK
(
console_owner_lock
);
static
struct
task_struct
*
console_owner
;
static
bool
console_waiter
;
/**
* console_lock_spinning_enable - mark beginning of code where another
* thread might safely busy wait
*
* This basically converts console_lock into a spinlock. This marks
* the section where the console_lock owner can not sleep, because
* there may be a waiter spinning (like a spinlock). Also it must be
* ready to hand over the lock at the end of the section.
*/
static
void
console_lock_spinning_enable
(
void
)
{
raw_spin_lock
(
&
console_owner_lock
);
console_owner
=
current
;
raw_spin_unlock
(
&
console_owner_lock
);
/* The waiter may spin on us after setting console_owner */
spin_acquire
(
&
console_owner_dep_map
,
0
,
0
,
_THIS_IP_
);
}
/**
* console_lock_spinning_disable_and_check - mark end of code where another
* thread was able to busy wait and check if there is a waiter
*
* This is called at the end of the section where spinning is allowed.
* It has two functions. First, it is a signal that it is no longer
* safe to start busy waiting for the lock. Second, it checks if
* there is a busy waiter and passes the lock rights to her.
*
* Important: Callers lose the lock if there was a busy waiter.
* They must not touch items synchronized by console_lock
* in this case.
*
* Return: 1 if the lock rights were passed, 0 otherwise.
*/
static
int
console_lock_spinning_disable_and_check
(
void
)
{
int
waiter
;
raw_spin_lock
(
&
console_owner_lock
);
waiter
=
READ_ONCE
(
console_waiter
);
console_owner
=
NULL
;
raw_spin_unlock
(
&
console_owner_lock
);
if
(
!
waiter
)
{
spin_release
(
&
console_owner_dep_map
,
1
,
_THIS_IP_
);
return
0
;
}
/* The waiter is now free to continue */
WRITE_ONCE
(
console_waiter
,
false
);
spin_release
(
&
console_owner_dep_map
,
1
,
_THIS_IP_
);
/*
* Hand off console_lock to waiter. The waiter will perform
* the up(). After this, the waiter is the console_lock owner.
*/
mutex_release
(
&
console_lock_dep_map
,
1
,
_THIS_IP_
);
return
1
;
}
/**
* console_trylock_spinning - try to get console_lock by busy waiting
*
* This allows to busy wait for the console_lock when the current
* owner is running in specially marked sections. It means that
* the current owner is running and cannot reschedule until it
* is ready to lose the lock.
*
* Return: 1 if we got the lock, 0 othrewise
*/
static
int
console_trylock_spinning
(
void
)
{
struct
task_struct
*
owner
=
NULL
;
bool
waiter
;
bool
spin
=
false
;
unsigned
long
flags
;
if
(
console_trylock
())
return
1
;
printk_safe_enter_irqsave
(
flags
);
raw_spin_lock
(
&
console_owner_lock
);
owner
=
READ_ONCE
(
console_owner
);
waiter
=
READ_ONCE
(
console_waiter
);
if
(
!
waiter
&&
owner
&&
owner
!=
current
)
{
WRITE_ONCE
(
console_waiter
,
true
);
spin
=
true
;
}
raw_spin_unlock
(
&
console_owner_lock
);
/*
* If there is an active printk() writing to the
* consoles, instead of having it write our data too,
* see if we can offload that load from the active
* printer, and do some printing ourselves.
* Go into a spin only if there isn't already a waiter
* spinning, and there is an active printer, and
* that active printer isn't us (recursive printk?).
*/
if
(
!
spin
)
{
printk_safe_exit_irqrestore
(
flags
);
return
0
;
}
/* We spin waiting for the owner to release us */
spin_acquire
(
&
console_owner_dep_map
,
0
,
0
,
_THIS_IP_
);
/* Owner will clear console_waiter on hand off */
while
(
READ_ONCE
(
console_waiter
))
cpu_relax
();
spin_release
(
&
console_owner_dep_map
,
1
,
_THIS_IP_
);
printk_safe_exit_irqrestore
(
flags
);
/*
* The owner passed the console lock to us.
* Since we did not spin on console lock, annotate
* this as a trylock. Otherwise lockdep will
* complain.
*/
mutex_acquire
(
&
console_lock_dep_map
,
0
,
1
,
_THIS_IP_
);
return
1
;
}
/*
/*
* Call the console drivers, asking them to write out
* Call the console drivers, asking them to write out
* log_buf[start] to log_buf[end - 1].
* log_buf[start] to log_buf[end - 1].
...
@@ -1752,13 +1892,20 @@ asmlinkage int vprintk_emit(int facility, int level,
...
@@ -1752,13 +1892,20 @@ asmlinkage int vprintk_emit(int facility, int level,
/* If called from the scheduler, we can not call up(). */
/* If called from the scheduler, we can not call up(). */
if
(
!
in_sched
)
{
if
(
!
in_sched
)
{
/*
* Disable preemption to avoid being preempted while holding
* console_sem which would prevent anyone from printing to
* console
*/
preempt_disable
();
/*
/*
* Try to acquire and then immediately release the console
* Try to acquire and then immediately release the console
* semaphore. The release will print out buffers and wake up
* semaphore. The release will print out buffers and wake up
* /dev/kmsg and syslog() users.
* /dev/kmsg and syslog() users.
*/
*/
if
(
console_trylock
())
if
(
console_trylock
_spinning
())
console_unlock
();
console_unlock
();
preempt_enable
();
}
}
return
printed_len
;
return
printed_len
;
...
@@ -1859,6 +2006,8 @@ static ssize_t msg_print_ext_header(char *buf, size_t size,
...
@@ -1859,6 +2006,8 @@ static ssize_t msg_print_ext_header(char *buf, size_t size,
static
ssize_t
msg_print_ext_body
(
char
*
buf
,
size_t
size
,
static
ssize_t
msg_print_ext_body
(
char
*
buf
,
size_t
size
,
char
*
dict
,
size_t
dict_len
,
char
*
dict
,
size_t
dict_len
,
char
*
text
,
size_t
text_len
)
{
return
0
;
}
char
*
text
,
size_t
text_len
)
{
return
0
;
}
static
void
console_lock_spinning_enable
(
void
)
{
}
static
int
console_lock_spinning_disable_and_check
(
void
)
{
return
0
;
}
static
void
call_console_drivers
(
const
char
*
ext_text
,
size_t
ext_len
,
static
void
call_console_drivers
(
const
char
*
ext_text
,
size_t
ext_len
,
const
char
*
text
,
size_t
len
)
{}
const
char
*
text
,
size_t
len
)
{}
static
size_t
msg_print_text
(
const
struct
printk_log
*
msg
,
static
size_t
msg_print_text
(
const
struct
printk_log
*
msg
,
...
@@ -2084,20 +2233,7 @@ int console_trylock(void)
...
@@ -2084,20 +2233,7 @@ int console_trylock(void)
return
0
;
return
0
;
}
}
console_locked
=
1
;
console_locked
=
1
;
/*
console_may_schedule
=
0
;
* When PREEMPT_COUNT disabled we can't reliably detect if it's
* safe to schedule (e.g. calling printk while holding a spin_lock),
* because preempt_disable()/preempt_enable() are just barriers there
* and preempt_count() is always 0.
*
* RCU read sections have a separate preemption counter when
* PREEMPT_RCU enabled thus we must take extra care and check
* rcu_preempt_depth(), otherwise RCU read sections modify
* preempt_count().
*/
console_may_schedule
=
!
oops_in_progress
&&
preemptible
()
&&
!
rcu_preempt_depth
();
return
1
;
return
1
;
}
}
EXPORT_SYMBOL
(
console_trylock
);
EXPORT_SYMBOL
(
console_trylock
);
...
@@ -2247,14 +2383,29 @@ void console_unlock(void)
...
@@ -2247,14 +2383,29 @@ void console_unlock(void)
console_seq
++
;
console_seq
++
;
raw_spin_unlock
(
&
logbuf_lock
);
raw_spin_unlock
(
&
logbuf_lock
);
/*
* While actively printing out messages, if another printk()
* were to occur on another CPU, it may wait for this one to
* finish. This task can not be preempted if there is a
* waiter waiting to take over.
*/
console_lock_spinning_enable
();
stop_critical_timings
();
/* don't trace print latency */
stop_critical_timings
();
/* don't trace print latency */
call_console_drivers
(
ext_text
,
ext_len
,
text
,
len
);
call_console_drivers
(
ext_text
,
ext_len
,
text
,
len
);
start_critical_timings
();
start_critical_timings
();
if
(
console_lock_spinning_disable_and_check
())
{
printk_safe_exit_irqrestore
(
flags
);
return
;
}
printk_safe_exit_irqrestore
(
flags
);
printk_safe_exit_irqrestore
(
flags
);
if
(
do_cond_resched
)
if
(
do_cond_resched
)
cond_resched
();
cond_resched
();
}
}
console_locked
=
0
;
console_locked
=
0
;
/* Release the exclusive_console once it is used */
/* Release the exclusive_console once it is used */
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录