On Thu, 28 Nov 2013 16:48:43 +0900 Joonsoo Kim <iamjoonsoo....@lge.com> wrote:
> Now, we have an infrastructure in rmap_walk() to handle difference > from variants of rmap traversing functions. > > So, just use it in try_to_unmap(). > > In this patch, I change following things. > > 1. enable rmap_walk() if !CONFIG_MIGRATION. > 2. mechanical change to use rmap_walk() in try_to_unmap(). > > ... > > --- a/include/linux/rmap.h > +++ b/include/linux/rmap.h > @@ -190,7 +190,7 @@ int page_referenced_one(struct page *, struct > vm_area_struct *, > > int try_to_unmap(struct page *, enum ttu_flags flags); > int try_to_unmap_one(struct page *, struct vm_area_struct *, > - unsigned long address, enum ttu_flags flags); > + unsigned long address, void *arg); This change is ugly and unchangelogged. Also, "enum ttu_flags flags" was nice and meaningful, but "void *arg" conveys far less information. A suitable way to address this shortcoming is to document `arg' at the try_to_unmap_one() definition site. try_to_unmap_one() doesn't actually have any documentation at this stage - let's please fix that? > > ... > > @@ -1509,6 +1510,11 @@ bool is_vma_temporary_stack(struct vm_area_struct *vma) > return false; > } > > +static int skip_vma_temporary_stack(struct vm_area_struct *vma, void *arg) > +{ > + return (int)is_vma_temporary_stack(vma); > +} The (int) cast is unneeded - the compiler will turn a bool into an int. Should this function (and rmap_walk_control.skip()) really be returning a bool? The name of this function is poor: "skip_foo" implies that the function will skip over a foo. But that isn't what this function does. Please choose something which accurately reflects the function's behavior. > /** > * try_to_unmap_anon - unmap or unlock anonymous page using the object-based > * rmap method > @@ -1554,7 +1560,7 @@ static int try_to_unmap_anon(struct page *page, enum > ttu_flags flags) > continue; > > address = vma_address(page, vma); > - ret = try_to_unmap_one(page, vma, address, flags); > + ret = try_to_unmap_one(page, vma, address, (void *)flags); > if (ret != SWAP_AGAIN || !page_mapped(page)) > break; > } > > ... > > /** > * try_to_unmap - try to remove all page table mappings to a page > * @page: the page to get unmapped > @@ -1630,16 +1641,30 @@ out: > int try_to_unmap(struct page *page, enum ttu_flags flags) > { > int ret; > + struct rmap_walk_control rwc; > > - BUG_ON(!PageLocked(page)); > VM_BUG_ON(!PageHuge(page) && PageTransHuge(page)); > > - if (unlikely(PageKsm(page))) > - ret = try_to_unmap_ksm(page, flags); > - else if (PageAnon(page)) > - ret = try_to_unmap_anon(page, flags); > - else > - ret = try_to_unmap_file(page, flags); > + memset(&rwc, 0, sizeof(rwc)); > + rwc.main = try_to_unmap_one; > + rwc.arg = (void *)flags; > + rwc.main_done = page_not_mapped; > + rwc.file_nonlinear = try_to_unmap_nonlinear; > + rwc.anon_lock = page_lock_anon_vma_read; struct rmap_walk_control rwc = { ... }; > + /* > + * During exec, a temporary VMA is setup and later moved. > + * The VMA is moved under the anon_vma lock but not the > + * page tables leading to a race where migration cannot > + * find the migration ptes. Rather than increasing the > + * locking requirements of exec(), migration skips > + * temporary VMAs until after exec() completes. > + */ > + if (flags & TTU_MIGRATION && !PageKsm(page) && PageAnon(page)) > + rwc.vma_skip = skip_vma_temporary_stack; > + > + ret = rmap_walk(page, &rwc); > + > if (ret != SWAP_MLOCK && !page_mapped(page)) > ret = SWAP_SUCCESS; > return ret; > > ... > -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/