X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fllite%2Frw26.c;h=18098dc5860d38ba682903ff98a597e634aa88d6;hb=110d8d4952a9de607cf21f648d75e0b05ef0cee1;hp=0a4b9a95d14c2737fadab0a0982cdf1ffa02cf2a;hpb=ff353fef1eca3cc4d4b492b9591c819c00f4e8dc;p=fs%2Flustre-release.git diff --git a/lustre/llite/rw26.c b/lustre/llite/rw26.c index 0a4b9a9..18098dc 100644 --- a/lustre/llite/rw26.c +++ b/lustre/llite/rw26.c @@ -118,49 +118,62 @@ static void ll_invalidatepage(struct page *vmpage, unsigned long offset) #endif static int ll_releasepage(struct page *vmpage, RELEASEPAGE_ARG_TYPE gfp_mask) { - struct cl_env_nest nest; - struct lu_env *env; - struct cl_object *obj; - struct cl_page *page; - struct address_space *mapping; - int result; + struct lu_env *env; + void *cookie; + struct cl_object *obj; + struct cl_page *page; + struct address_space *mapping; + int result = 0; + + LASSERT(PageLocked(vmpage)); + if (PageWriteback(vmpage) || PageDirty(vmpage)) + return 0; + + mapping = vmpage->mapping; + if (mapping == NULL) + return 1; + + obj = ll_i2info(mapping->host)->lli_clob; + if (obj == NULL) + return 1; + + /* 1 for caller, 1 for cl_page and 1 for page cache */ + if (page_count(vmpage) > 3) + return 0; + + page = cl_vmpage_page(vmpage, obj); + if (page == NULL) + return 1; + + cookie = cl_env_reenter(); + env = cl_env_percpu_get(); + LASSERT(!IS_ERR(env)); + + if (!cl_page_in_use(page)) { + result = 1; + cl_page_delete(env, page); + } - LASSERT(PageLocked(vmpage)); - if (PageWriteback(vmpage) || PageDirty(vmpage)) - return 0; - - mapping = vmpage->mapping; - if (mapping == NULL) - return 1; - - obj = ll_i2info(mapping->host)->lli_clob; - if (obj == NULL) - return 1; - - /* 1 for page allocator, 1 for cl_page and 1 for page cache */ - if (page_count(vmpage) > 3) - return 0; - - /* TODO: determine what gfp should be used by @gfp_mask. */ - env = cl_env_nested_get(&nest); - if (IS_ERR(env)) - /* If we can't allocate an env we won't call cl_page_put() - * later on which further means it's impossible to drop - * page refcount by cl_page, so ask kernel to not free - * this page. */ - return 0; - - page = cl_vmpage_page(vmpage, obj); - result = page == NULL; - if (page != NULL) { - if (!cl_page_in_use(page)) { - result = 1; - cl_page_delete(env, page); - } - cl_page_put(env, page); - } - cl_env_nested_put(&nest, env); - return result; + /* To use percpu env array, the call path can not be rescheduled; + * otherwise percpu array will be messed if ll_releaspage() called + * again on the same CPU. + * + * If this page holds the last refc of cl_object, the following + * call path may cause reschedule: + * cl_page_put -> cl_page_free -> cl_object_put -> + * lu_object_put -> lu_object_free -> lov_delete_raid0 -> + * cl_locks_prune. + * + * However, the kernel can't get rid of this inode until all pages have + * been cleaned up. Now that we hold page lock here, it's pretty safe + * that we won't get into object delete path. + */ + LASSERT(cl_object_refc(obj) > 1); + cl_page_put(env, page); + + cl_env_percpu_put(env); + cl_env_reexit(cookie); + return result; } static int ll_set_page_dirty(struct page *vmpage)