Messages in this thread | | | Date | Mon, 13 Feb 2017 16:43:45 +0300 | From | "Kirill A. Shutemov" <> | Subject | Re: [PATCHv6 01/37] mm, shmem: swich huge tmpfs to multi-order radix-tree entries |
| |
On Thu, Feb 09, 2017 at 07:58:20PM +0300, Kirill A. Shutemov wrote: > I'll look into it.
I ended up with this (I'll test it more later):
void filemap_map_pages(struct vm_fault *vmf, pgoff_t start_pgoff, pgoff_t end_pgoff) { struct radix_tree_iter iter; void **slot; struct file *file = vmf->vma->vm_file; struct address_space *mapping = file->f_mapping; pgoff_t last_pgoff = start_pgoff; loff_t size; struct page *page; bool mapped;
rcu_read_lock(); radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start_pgoff) { unsigned long index = iter.index; if (index < start_pgoff) index = start_pgoff; if (index > end_pgoff) break; repeat: page = radix_tree_deref_slot(slot); if (unlikely(!page)) continue; if (radix_tree_exception(page)) { if (radix_tree_deref_retry(page)) slot = radix_tree_iter_retry(&iter); continue; }
if (!page_cache_get_speculative(page)) goto repeat;
/* Has the page moved? */ if (unlikely(page != *slot)) { put_page(page); goto repeat; }
/* For multi-order entries, find relevant subpage */ page = find_subpage(page, index);
if (!PageUptodate(page) || PageReadahead(page)) goto skip; if (!trylock_page(page)) goto skip;
if (page_mapping(page) != mapping || !PageUptodate(page)) goto skip_unlock;
size = round_up(i_size_read(mapping->host), PAGE_SIZE); if (compound_head(page)->index >= size >> PAGE_SHIFT) goto skip_unlock;
if (file->f_ra.mmap_miss > 0) file->f_ra.mmap_miss--; map_next_subpage: if (PageHWPoison(page)) goto next;
vmf->address += (index - last_pgoff) << PAGE_SHIFT; if (vmf->pte) vmf->pte += index - last_pgoff; last_pgoff = index; mapped = !alloc_set_pte(vmf, NULL, page);
/* Huge page is mapped or last index? No need to proceed. */ if (pmd_trans_huge(*vmf->pmd) || index == end_pgoff) { unlock_page(page); break; } next: if (page && PageCompound(page)) { /* Last subpage handled? */ if ((index & (compound_nr_pages(page) - 1)) == compound_nr_pages(page) - 1) goto skip_unlock; index++; page++;
/* * One page reference goes to page table mapping. * Need additional reference, if last alloc_set_pte() * succeed. */ if (mapped) get_page(page); goto map_next_subpage; } skip_unlock: unlock_page(page); skip: iter.index = compound_head(page)->index + compound_nr_pages(page) - 1; /* Only give up reference if alloc_set_pte() failed. */ if (!mapped) put_page(page); } rcu_read_unlock(); }
-- Kirill A. Shutemov
| |