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). 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:
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é:
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
.