no_console_suspend

转自 https://blog.csdn.net/tiantao2012/article/details/52330621

通过uboot 可以传递给kernel一个no_console_suspend的参数。
这个参数的意思是,在suspend的时候console 不进行suspend,否则console suspend之后其他driver在suspend 过程中印的log都显示不出来,因此加这个参数一般用于调试suspend 和 resume。
我们看看是如何kernel是如何是实现的.

http://lxr.free-electrons.com/source/kernel/printk/printk.c

2009 bool console_suspend_enabled = true;
2010 EXPORT_SYMBOL(console_suspend_enabled);
2011 
2012 static int __init console_suspend_disable(char *str)
2013 {
2014         console_suspend_enabled = false;
2015         return 1;
2016 }
2017 __setup("no_console_suspend", console_suspend_disable);


kernel 用console_suspend_disable 来接收no_console_suspend,可见如果uboot 传递这个参数,则console_suspend_enabled = false


kernel 在suspend 过程会调用suspend_console 来suspend console,可见如果console_suspend_enabled=false的话,这个函数在2031行就返回了,console 就不进行suspend 过程了,这样其他driver就可以继续使用printk来打印log


2028 void suspend_console(void)
2029 {
2030         if (!console_suspend_enabled)
2031                 return;
2032         printk("Suspending console(s) (use no_console_suspend to debug)\n");
2033         console_lock();
2034         console_suspended = 1;
2035         up_console_sem();
2036 }

我们现在看看suspend_console 是如何阻止log显示的,

我们先看看prink的callstack
printk->vprintk_emit->console_trylock

2100 int console_trylock(void)
2101 {
2102         if (down_trylock_console_sem())
2103                 return 0;
2104         if (console_suspended) {
2105                 up_console_sem();
2106                 return 0;
2107         }
2108         console_locked = 1;
2120         console_may_schedule = !oops_in_progress &&
2121                         preemptible() &&
2122                         !rcu_preempt_depth();
2123         return 1;
2124 }


继续调用down_trylock_console_sem
110 static int __down_trylock_console_sem(unsigned long ip)
111 {
112         if (down_trylock(&console_sem))
113                 return 1;
114         mutex_acquire(&console_lock_dep_map, 0, 1, ip);
115         return 0;
116 }

这个函数回去获取console_sem 锁,但是由于我们已经在suspend_console 的时候调用down_console_sem 已经获取了这个锁,一次这里肯定是返回0的,所以不会调用
2080 void console_lock(void)
2081 {
2082         might_sleep();
2083 
2084         down_console_sem();
2085         if (console_suspended)
2086                 return;
2087         console_locked = 1;
2088         console_may_schedule = 1;
2089 }
down_console_sem 实现如下:


105 #define down_console_sem() do { \
106         down(&console_sem);\
107         mutex_acquire(&console_lock_dep_map, 0, 0, _RET_IP_);\
108 } while (0)

所有由于 vprintk_emit 中的console_trylock() 返回0,所以不会调用 console_unlock()来印log

正常情况下 vprintk_emit 中的console_trylock() 返回1,所以会调用 console_unlock()来印log
我们看看console_unlock的实现
2203 void console_unlock(void)
2204 {
  call_console_drivers
2340 }

调用call_console_drivers
1434 static void call_console_drivers(int level,
1435                                  const char *ext_text, size_t ext_len,
1436                                  const char *text, size_t len)
1437 {
1438         struct console *con;
1439 
1440         trace_console(text, len);
1441 
1442         if (level >= console_loglevel && !ignore_loglevel)
1443                 return;
1444         if (!console_drivers)
1445                 return;
1446 
1447         for_each_console(con) {
1448                 if (exclusive_console && con != exclusive_console)
1449                         continue;
1450                 if (!(con->flags & CON_ENABLED))
1451                         continue;
1452                 if (!con->write)
1453                         continue;
1454                 if (!cpu_online(smp_processor_id()) &&
1455                     !(con->flags & CON_ANYTIME))
1456                         continue;
1457                 if (con->flags & CON_EXTENDED)
1458                         con->write(con, ext_text, ext_len);
1459                 else
1460                         con->write(con, text, len);
1461         }
1462 }


最终通过con->write将log显示到控制台上

猜你喜欢

转载自blog.csdn.net/wenjin359/article/details/83054882
今日推荐