fbdev/defio: Early-out if page is already enlisted
Return early if a page is already in the list of dirty pages for deferred I/O. This can be detected if the page's list head is not empty. Keep the list head initialized while the page is not enlisted to make this work reliably. v2: * update comment and fix spelling (Sam) Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de> Acked-by: Sam Ravnborg <sam@ravnborg.org> Link: https://patchwork.freedesktop.org/patch/msgid/20220211094640.21632-2-tzimmermann@suse.de
This commit is contained in:
Родитель
21d26b3972
Коммит
105a940416
|
@ -59,6 +59,7 @@ static vm_fault_t fb_deferred_io_fault(struct vm_fault *vmf)
|
|||
printk(KERN_ERR "no mapping available\n");
|
||||
|
||||
BUG_ON(!page->mapping);
|
||||
INIT_LIST_HEAD(&page->lru);
|
||||
page->index = vmf->pgoff;
|
||||
|
||||
vmf->page = page;
|
||||
|
@ -122,17 +123,24 @@ static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf)
|
|||
*/
|
||||
lock_page(page);
|
||||
|
||||
/*
|
||||
* This check is to catch the case where a new process could start
|
||||
* writing to the same page through a new PTE. This new access
|
||||
* can cause a call to .page_mkwrite even if the original process'
|
||||
* PTE is marked writable.
|
||||
*
|
||||
* TODO: The lru field is owned by the page cache; hence the name.
|
||||
* We dequeue in fb_deferred_io_work() after flushing the
|
||||
* page's content into video memory. Instead of lru, fbdefio
|
||||
* should have it's own field.
|
||||
*/
|
||||
if (!list_empty(&page->lru))
|
||||
goto page_already_added;
|
||||
|
||||
/* we loop through the pagelist before adding in order
|
||||
to keep the pagelist sorted */
|
||||
list_for_each_entry(cur, &fbdefio->pagelist, lru) {
|
||||
/* this check is to catch the case where a new
|
||||
process could start writing to the same page
|
||||
through a new pte. this new access can cause the
|
||||
mkwrite even when the original ps's pte is marked
|
||||
writable */
|
||||
if (unlikely(cur == page))
|
||||
goto page_already_added;
|
||||
else if (cur->index > page->index)
|
||||
if (cur->index > page->index)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -194,7 +202,7 @@ static void fb_deferred_io_work(struct work_struct *work)
|
|||
|
||||
/* clear the list */
|
||||
list_for_each_safe(node, next, &fbdefio->pagelist) {
|
||||
list_del(node);
|
||||
list_del_init(node);
|
||||
}
|
||||
mutex_unlock(&fbdefio->lock);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче