/dev/oldmem


/dev/oldmemって言うデバイス。カーネルオプションCONFIG_CRASH_DUMPで作成され、カーネルクラッシュ時のダンプを取得するためのものらしいですが、よく分かりませんね。クラッシュしたカーネル下でダンプするのは、カーネルが不安定になっていて、よろしくない。と言うことなんでしょう。

そこで登場するのが、kexec。これはカーネル下に、前もって別のカーネルイメージを置いといて、カーネルがクラッシュした場合、このカーネルと差し替える。と言うものだそうです。そして、差し替えたカーネル下で、クラッシュしたカーネルダンプを取得する。と言う按配だそうで・・・。まあ、その時、クラッシュカーネルのダンプは、できるだけカーネルの負荷がないように(この時点では、クラッシュしたカーネルで動作する必要あり。たぶん)、で、単にどっかの物理メモリに退避させるだけ。

カーネルを差し替えるって、プロセス切り替えみたいな。かんじでなく、カーネルは物理ストレートマップしていて、従って、クラッシュしたカーネルの物理メモリーに、新しいカーネルを転送する(上書き)必要があります。その時、クラッシュしたカーネルのイメージを、カーネル空間外の連続するページに蓄えておいて、そのページを新しいカーネル下で、安心して取得しようと言う物らしいです。

とりあえず、以下がソース
#ifdef CONFIG_CRASH_DUMP
static const struct file_operations oldmem_fops = {
       .read   = read_oldmem,
       .open   = open_oldmem,
       .llseek = default_llseek,
};
#endif
pposからページサイズ毎に、copy_oldmem_page()で取得しているようで。pposには、新しいカーネルが機動する時に、クラッシュしたカーネルをダンプしている、物理アドレスが設定されているんじゃないでしょうか?
static ssize_t read_oldmem(struct file *file, char __user *buf,
                               size_t count, loff_t *ppos)
{
       unsigned long pfn, offset;
       size_t read = 0, csize;
       int rc = 0;

       while (count) {
               pfn = *ppos / PAGE_SIZE;
               if (pfn > saved_max_pfn)
                       return read;

               offset = (unsigned long)(*ppos % PAGE_SIZE);
               if (count > PAGE_SIZE - offset)
                       csize = PAGE_SIZE - offset;
               else
                       csize = count;

               rc = copy_oldmem_page(pfn, buf, csize, offset, 1);
               if (rc < 0)
                       return rc;
               buf += csize;
               *ppos += csize;
               read += csize;
               count -= csize;
       }
       return read;
}
copy_oldmem_page()で、クラッシュしたカーネルの物理ページ(ページフレーム)で、ページ単位に取得しています。(いま一つ分からん。) まあ、/dev/memと異なって、ページフレーム毎に仮想アドレスをアサインしながら、buffに複写する必要があります。

なお、引数のchar *bufは、ユーザ空間/カーネル空間のケースでの呼び出しがあるらしく、userbuf引数が1の時、bufはユーザ空間と言うことらしく、その場合、kdump_buf_pageにcopy_page()で1ページ分複写して、それをcopy_to_user()でユーザ空間buffに複写していますが、なぜvaddrでcopy_to_user()しないんでしょうかね・・・。
ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
                              size_t csize, unsigned long offset, int userbuf)
{
       void  *vaddr;

       if (!csize)
               return 0;

       if (!is_crashed_pfn_valid(pfn))
               return -EFAULT;

       vaddr = kmap_atomic_pfn(pfn);

       if (!userbuf) {
               memcpy(buf, (vaddr + offset), csize);
               kunmap_atomic(vaddr, KM_PTE0);
       } else {
               if (!kdump_buf_page) {
                       printk(KERN_WARNING "Kdump: Kdump buffer page not"
                               " allocated\n");
                       kunmap_atomic(vaddr, KM_PTE0);
                       return -EFAULT;
               }
               copy_page(kdump_buf_page, vaddr);
               kunmap_atomic(vaddr, KM_PTE0);
               if (copy_to_user(buf, (kdump_buf_page + offset), csize))
                       return -EFAULT;
       }

       return csize;
}
/dev/oldmemって、我々がお世話になることは絶対無い。って言うデバイスってことでした。

最終更新 2012/07/06 21:54:03 - north
(2012/07/06 21:54:03 作成)


検索

アクセス数
3586035
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。