無料Wikiサービス | デモページ
検索

アクセス数
最近のコメント
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
はじめ - ノース
はじめ - ノース
はじめ - 楽打連動ユーザー
はじめ - 楽打連動ユーザー
Adsense
広告情報が設定されていません。

klogd


ログファイルとロギングの仕組みのklogdについて記事を読んで、成る程。という思い出でした。それを踏まえてこの記事をアップします。従って内容的には先のシステムログ1/システムログ2の焼き直しみたいなものです。

klogdとカーネルのログデーモンと言う事で、カーネルスレッドと思ってしまいそうですが、ログファイルとロギングの仕組みの図解のように、ユーザランドから起動されるもので、もちろんユーザプロセスです。(なお、図解ではdmesgも/proc/kmsgから取得するようになっていますが、私の調べたレベルではdmesgは直接リングバッファから取得しているようです。)

/proc/kmsgから読み出すと、do_syslog()をtype=2でコールしていました。その処理はlog_start - log_end=0なら、log_waitキューでウエイトさせていました。
DECLARE_WAIT_QUEUE_HEAD(log_wait);
int do_syslog(int type, char __user *buf, int len)
{
  :
       switch (type) {
  :
       case 2:         /* Read from log */
  :
               error = wait_event_interruptible(log_wait,
                                                       (log_start - log_end));
  :
       default:
               error = -EINVAL;
               break;
       }
out:
       return error;
}

#define wait_event_interruptible(wq, condition)                         \
({                                                                      \
       int __ret = 0;                                                  \
       if (!(condition))                                               \
               __wait_event_interruptible(wq, condition, __ret);       \
       __ret;                                                          \
})
そしてそのウエイトを起床させるのが、printk()の下位関数であるvprintk()で、コンソール出力時の呼び出されるrelease_console_sem()です。release_console_sem()ではwake_klogd |= log_start - log_endととし、それが0でないならwake_up_klogd()としてklogdを起床させるものです。
(forループの中で論理和としている意味はよくわかりません。)
asmlinkage int vprintk(const char *fmt, va_list args)
{
  :
       if (acquire_console_semaphore_for_printk(this_cpu))
               release_console_sem();
  :
}

void release_console_sem(void)
{
  :
       unsigned wake_klogd = 0;
  :
       for ( ; ; ) {
               spin_lock_irqsave(&logbuf_lock, flags);
               wake_klogd |= log_start - log_end;
  :
       }
  :
      if (wake_klogd)
               wake_up_klogd();
}
wake_up_klogd()と、いかにもklogdスレッドを起床させるかのようですが、要はlog_waitキューでウエイトしているプロセスを起動させているに過ぎません。いうなればcat /proc/kmsgでウエイトしているなら、カーネルからみたらこれがklogプロセスというわけです。
void wake_up_klogd(void)
{
       if (!oops_in_progress && waitqueue_active(&log_wait))
               wake_up_interruptible(&log_wait);
}
本実装はcat /proc/kmsgで表示するためのもでなく、カーネルからprinkされることでユーザプロセスを起動させる仕組みだったのかと妙に納得したところです。なお、klogdが起動していて、cat /proc/kmsgを実行させると、ウエイト順にその時のシスログを処理することになるかと思います。

補足

cat /proc/kmsgがklogプロセスになるというのは、cat /proc/kmsgはsys_readのシステムコールされます。/proc/kmsgのファイル読み込みのコールバック関数は、do_syslog()をtype=2でコールします。従ってシステムログのリングバッファにデータがない場合、catプロセスがlog_waitにリストされると言うことです。

最終更新 2012/07/06 03:31:38 - north
(2011/08/06 03:29:16 作成)