- struct cl_page *page = NULL;
- struct cl_page *ghost = NULL;
- struct cl_object_header *hdr;
- int err;
-
- LASSERT(type == CPT_CACHEABLE || type == CPT_TRANSIENT);
- cfs_might_sleep();
-
- ENTRY;
-
- hdr = cl_object_header(o);
- CS_PAGE_INC(o, lookup);
-
- CDEBUG(D_PAGE, "%lu@"DFID" %p %lx %d\n",
- idx, PFID(&hdr->coh_lu.loh_fid), vmpage, vmpage->private, type);
- /* fast path. */
- if (type == CPT_CACHEABLE) {
- /* cl_page::cp_lock is used to protect the page state and
- * refcount, but need an external lock to protect the
- * child/parent relationship, so vmpage lock must be held for
- * this purpose. */
- KLASSERT(PageLocked(vmpage));
- /*
- * cl_vmpage_page() can be called here without any locks as
- *
- * - "vmpage" is locked (which prevents ->private from
- * concurrent updates), and
- *
- * - "o" cannot be destroyed while current thread holds a
- * reference on it.
- */
- page = cl_vmpage_page(vmpage, o);
- PINVRNT(env, page,
- ergo(page != NULL,
- cl_page_vmpage(env, page) == vmpage &&
- (void *)radix_tree_lookup(&hdr->coh_tree,
- idx) == page));
- }
-
- if (page != NULL) {
- CS_PAGE_INC(o, hit);
- RETURN(page);
- }
-
- /* allocate and initialize cl_page */
- err = cl_page_alloc(env, o, idx, vmpage, type, &page);
- if (err != 0)
- RETURN(page);
-
- if (type == CPT_TRANSIENT) {
- if (parent) {
- LASSERT(page->cp_parent == NULL);
- page->cp_parent = parent;
- parent->cp_child = page;
- }
- RETURN(page);
- }
-
- /*
- * XXX optimization: use radix_tree_preload() here, and change tree
- * gfp mask to GFP_KERNEL in cl_object_header_init().
- */
- spin_lock(&hdr->coh_page_guard);
- err = radix_tree_insert(&hdr->coh_tree, idx, page);
- if (err != 0) {
- ghost = page;
- /*
- * Noted by Jay: a lock on \a vmpage protects cl_page_find()
- * from this race, but
- *
- * 0. it's better to have cl_page interface "locally
- * consistent" so that its correctness can be reasoned
- * about without appealing to the (obscure world of) VM
- * locking.
- *
- * 1. handling this race allows ->coh_tree to remain
- * consistent even when VM locking is somehow busted,
- * which is very useful during diagnosing and debugging.
- */
- page = ERR_PTR(err);
- CL_PAGE_DEBUG(D_ERROR, env, ghost,
- "fail to insert into radix tree: %d\n", err);
- } else {
- if (parent) {
- LASSERT(page->cp_parent == NULL);
- page->cp_parent = parent;
- parent->cp_child = page;
- }
- hdr->coh_pages++;
- }
- spin_unlock(&hdr->coh_page_guard);
-
- if (unlikely(ghost != NULL)) {
- CS_PAGE_DEC(o, busy);
- cl_page_delete0(env, ghost, 0);
- cl_page_free(env, ghost);
- }
- RETURN(page);
-}