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

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

VDSO_COMPTの/proc/pid/mapsのvdso


CONFIG_X86_32の/proc/sys/vm/vdso_enabled=2(VDSO_COMPT)の時、カーネル空間に割り当てられたシステムコールは、ユーザ空間にマップされない。しかし/proc/pid/mapsで見ると、この処理はタスクのmmにリストされているvm_area_structを、順次表示しているにかかわらず、VDSO部も表示される。

まず、/proc/pid/mapsの処理の概略から。
/proc/pid/mapsが作成されると(inodeが作成されると)、そのiノードのコールバック関数に、proc_maps_operationsが設定される。このiノードがオープンされると、このコールバック関数の.open=maps_open()がコールされ、file->private_dataにproc_pid_maps_opコールバック関数が設定されることで、file_operationsのシーケンスファイル読み込み関数で、/proc/pid/mapsにかかる処理が行われることで実現する。
static const struct seq_operations proc_pid_maps_op = {
       .start  = m_start,
       .next   = m_next,
       .stop   = m_stop,
       .show   = show_map
};

const struct file_operations proc_maps_operations = {
       .open           = maps_open,
       .read           = seq_read,
       .llseek         = seq_lseek,
       .release        = seq_release_private,
};

static int maps_open(struct inode *inode, struct file *file)
{
       return do_maps_open(inode, file, &proc_pid_maps_op);
}
m_start()は読み込み開始時にコールされ、読み込みプロセスIDのmm_structを取得して、セマフォを取得する。そしてget_gate_vma()をコールして、VDSOのvm_area_structを取得し、それをpriv->tail_vma = tail_vmaとすることで、 タスクのmm_structに登録されてないVDSOケースでも、/proc/pid/mapsで表示されるようになっている。
static void *m_start(struct seq_file *m, loff_t *pos)
{
       struct proc_maps_private *priv = m->private;
       unsigned long last_addr = m->version;
       struct mm_struct *mm;
       struct vm_area_struct *vma, *tail_vma = NULL;
       loff_t l = *pos;

       priv->task = NULL;
       priv->tail_vma = NULL;
 
       if (last_addr == -1UL)
               return NULL;

       priv->task = get_pid_task(priv->pid, PIDTYPE_PID);
       if (!priv->task)
               return ERR_PTR(-ESRCH);

       mm = mm_for_maps(priv->task);
       if (!mm || IS_ERR(mm))
               return mm;
       down_read(&mm->mmap_sem);

       tail_vma = get_gate_vma(priv->task->mm);
       priv->tail_vma = tail_vma;

       vma = find_vma(mm, last_addr);
       if (last_addr && vma) {
               vma = vma->vm_next;
               goto out;
       }

       vma = NULL;
       if ((unsigned long)l < mm->map_count) {
               vma = mm->mmap;
               while (l-- && vma)
                       vma = vma->vm_next;
               goto out;
       }

       if (l != mm->map_count)
               tail_vma = NULL; /* After gate vma */

out:
       if (vma)
               return vma;

       m->version = (tail_vma != NULL)? 0: -1UL;
       up_read(&mm->mmap_sem);
       mmput(mm);
       return tail_vma;
}
VDSOを割り当てるarch_setup_additional_pages()で、current->mm->context.vdso = (void *)addrとしていて、そのアドレスがVDSO_HIGH_BASEの時、VDSO_COMPATと言うこと。で、gate_vmaが返される。
struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
{
       if (mm && mm->context.vdso == (void *)VDSO_HIGH_BASE)
               return &gate_vma;
       return NULL;
}
なお、gate_vmaは、vdso32-setup時に以下の様に作成されている。
static int __init gate_vma_init(void)
{
       gate_vma.vm_mm = NULL;
       gate_vma.vm_start = FIXADDR_USER_START;
       gate_vma.vm_end = FIXADDR_USER_END;
       gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC;
       gate_vma.vm_page_prot = __P101;
       gate_vma.vm_flags |= VM_ALWAYSDUMP;
       return 0;
}

補足

上記内容は32ビットカーネルについて。64ビットカーネルの実装は異なる。


最終更新 2012/07/15 16:28:27 - north
(2012/07/15 16:28:27 作成)