Comment mapper des pages à l’aide du gestionnaire de défauts de page?

Je souhaite utiliser le gestionnaire de pagefault de mon struct vm_area_struct * pour mapper une page physique sur un espace utilisateur.

Voici comment je procède:

  • alloc_page(GFP_USER) globalement une page en utilisant alloc_page(GFP_USER) lors de l’initialisation du module (j’ai essayé divers GFP).
  • Je crée une struct vm_area_struct , définit un gestionnaire de pagefault personnalisé et vma le vma à vma current->mm .

Lorsqu’une erreur de page se produit:

  • Je vmf->page à la page que j’ai précédemment allouée et renvoie 0.

Le résultat est que chaque page virtuelle de la vma doit être mappée sur la même page physique après une défaillance de page.

Mais voici ce que j’ai remarqué:

  • Lorsque j’écris sur la page de mon module de kernel, cela se reflète dans mon programme d’espace utilisateur.
  • Lorsque j’écris sur la page à partir de mon espace utilisateur, je ne la vois pas dans mon module de kernel.
  • Lorsque j’utilise get_user_pages dans mon module de kernel pour obtenir la page (au lieu d’utiliser ma variable globale), j’obtiens une adresse physique différente de celle de la variable de page globale. page_to_phys(page) l’adresse en utilisant page_to_phys(page) . L’écriture sur cette page est reflétée dans mon programme d’espace utilisateur.

Tout cela est fait dans le gestionnaire de fautes de page en passant.

Comment expliquer ce comportement curieux?

Pour accéder à la page depuis l’espace kernel, j’utilise kmap_atomic et kunmap_atomic .

Cela est dû au mécanisme de copie sur écriture. Une fois que votre gestionnaire d’erreur de page s’est exécuté, la page que vous avez renvoyée dans vmf->page est copiée dans une nouvelle page allouée. C’est pourquoi vos modifications dans l’espace utilisateur ne sont pas reflétées dans votre module de kernel. La page que vous tentiez de lire dans le kernel n’est pas celle qui a été réellement mappée dans votre processus d’espace utilisateur.

Vous pouvez vous référer à la fonction do_cow_fault dans mm/memory.c .