* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2015, Intel Corporation.
+ * Copyright (c) 2011, 2017, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
*
*/
-static void vvp_page_fini_common(struct vvp_page *vpg)
+static void vvp_page_fini_common(struct vvp_page *vpg, struct pagevec *pvec)
{
struct page *vmpage = vpg->vpg_page;
LASSERT(vmpage != NULL);
- put_page(vmpage);
+ if (pvec) {
+ if (!pagevec_add(pvec, vmpage))
+ pagevec_release(pvec);
+ } else {
+ put_page(vmpage);
+ }
}
static void vvp_page_fini(const struct lu_env *env,
- struct cl_page_slice *slice)
+ struct cl_page_slice *slice,
+ struct pagevec *pvec)
{
struct vvp_page *vpg = cl2vvp_page(slice);
struct page *vmpage = vpg->vpg_page;
* VPG_FREEING state.
*/
LASSERT((struct cl_page *)vmpage->private != slice->cpl_page);
- vvp_page_fini_common(vpg);
+ vvp_page_fini_common(vpg, pvec);
}
static int vvp_page_own(const struct lu_env *env,
struct vvp_page *vpg = cl2vvp_page(slice);
struct page *vmpage = vpg->vpg_page;
+ ENTRY;
+
LASSERT(vmpage != NULL);
if (nonblock) {
if (!trylock_page(vmpage))
lock_page(vmpage);
wait_on_page_writeback(vmpage);
- return 0;
+ RETURN(0);
}
static void vvp_page_assume(const struct lu_env *env,
{
struct page *vmpage = cl2vm_page(slice);
+ ENTRY;
+
LASSERT(vmpage != NULL);
LASSERT(PageLocked(vmpage));
unlock_page(cl2vm_page(slice));
+
+ EXIT;
}
static void vvp_page_discard(const struct lu_env *env,
LASSERT(vmpage != NULL);
LASSERT(PageLocked(vmpage));
- if (vpg->vpg_defer_uptodate && !vpg->vpg_ra_used)
+ if (vpg->vpg_defer_uptodate && !vpg->vpg_ra_used && vmpage->mapping)
ll_ra_stats_inc(vmpage->mapping->host, RA_STAT_DISCARDED);
- ll_invalidate_page(vmpage);
+ generic_error_remove_page(vmpage->mapping, vmpage);
}
static void vvp_page_delete(const struct lu_env *env,
const struct cl_page_slice *slice)
{
struct page *vmpage = cl2vm_page(slice);
- struct inode *inode = vmpage->mapping->host;
- struct cl_object *obj = slice->cpl_obj;
struct cl_page *page = slice->cpl_page;
int refc;
LASSERT(PageLocked(vmpage));
LASSERT((struct cl_page *)vmpage->private == page);
- LASSERT(inode == vvp_object_inode(obj));
+
/* Drop the reference count held in vvp_page_init */
refc = atomic_dec_return(&page->cp_ref);
struct cl_io *unused)
{
struct page *vmpage = cl2vm_page(slice);
+ struct cl_page *pg = slice->cpl_page;
LASSERT(PageLocked(vmpage));
LASSERT(!PageDirty(vmpage));
- set_page_writeback(vmpage);
+ /* ll_writepage path is not a sync write, so need to set page writeback
+ * flag */
+ if (pg->cp_sync_io == NULL)
+ set_page_writeback(vmpage);
return 0;
}
else
set_bit(AS_EIO, &inode->i_mapping->flags);
- if ((ioret == -ESHUTDOWN || ioret == -EINTR) &&
- obj->vob_discard_page_warned == 0) {
+ if ((ioret == -ESHUTDOWN || ioret == -EINTR ||
+ ioret == -EIO) && obj->vob_discard_page_warned == 0) {
obj->vob_discard_page_warned = 1;
ll_dirty_page_discard_warn(vmpage, ioret);
}
if (ioret == 0) {
if (!vpg->vpg_defer_uptodate)
cl_page_export(env, page, 1);
- } else {
+ } else if (vpg->vpg_defer_uptodate) {
vpg->vpg_defer_uptodate = 0;
+ if (ioret == -EWOULDBLOCK) {
+ /* mirror read failed, it needs to destroy the page
+ * because subpage would be from wrong osc when trying
+ * to read from a new mirror */
+ generic_error_remove_page(vmpage->mapping, vmpage);
+ }
}
if (page->cp_sync_io == NULL)
struct page *vmpage = vpg->vpg_page;
ENTRY;
- LASSERT(ergo(pg->cp_sync_io != NULL, PageLocked(vmpage)));
- LASSERT(PageWriteback(vmpage));
-
CL_PAGE_HEADER(D_PAGE, env, pg, "completing WRITE with %d\n", ioret);
- /*
- * Only mark the page error only when it's an async write because
- * applications won't wait for IO to finish.
- */
- if (pg->cp_sync_io == NULL)
+ if (pg->cp_sync_io != NULL) {
+ LASSERT(PageLocked(vmpage));
+ LASSERT(!PageWriteback(vmpage));
+ } else {
+ LASSERT(PageWriteback(vmpage));
+ /*
+ * Only mark the page error only when it's an async write
+ * because applications won't wait for IO to finish.
+ */
vvp_vmpage_error(vvp_object_inode(pg->cp_obj), vmpage, ioret);
- end_page_writeback(vmpage);
+ end_page_writeback(vmpage);
+ }
EXIT;
}
},
};
-static int vvp_transient_page_prep(const struct lu_env *env,
- const struct cl_page_slice *slice,
- struct cl_io *unused)
-{
- ENTRY;
- /* transient page should always be sent. */
- RETURN(0);
-}
-
-static void vvp_transient_page_verify(const struct cl_page *page)
-{
-}
-
-static int vvp_transient_page_own(const struct lu_env *env,
- const struct cl_page_slice *slice,
- struct cl_io *unused, int nonblock)
-{
- vvp_transient_page_verify(slice->cpl_page);
- return 0;
-}
-
-static void vvp_transient_page_assume(const struct lu_env *env,
- const struct cl_page_slice *slice,
- struct cl_io *unused)
-{
- vvp_transient_page_verify(slice->cpl_page);
-}
-
-static void vvp_transient_page_unassume(const struct lu_env *env,
- const struct cl_page_slice *slice,
- struct cl_io *unused)
-{
- vvp_transient_page_verify(slice->cpl_page);
-}
-
-static void vvp_transient_page_disown(const struct lu_env *env,
- const struct cl_page_slice *slice,
- struct cl_io *unused)
-{
- vvp_transient_page_verify(slice->cpl_page);
-}
-
static void vvp_transient_page_discard(const struct lu_env *env,
const struct cl_page_slice *slice,
struct cl_io *unused)
{
struct cl_page *page = slice->cpl_page;
- vvp_transient_page_verify(slice->cpl_page);
-
/*
* For transient pages, remove it from the radix tree.
*/
static int vvp_transient_page_is_vmlocked(const struct lu_env *env,
const struct cl_page_slice *slice)
{
- struct inode *inode = vvp_object_inode(slice->cpl_obj);
- int locked;
-
- locked = !inode_trylock(inode);
- if (!locked)
- inode_unlock(inode);
- return locked ? -EBUSY : -ENODATA;
-}
-
-static void
-vvp_transient_page_completion(const struct lu_env *env,
- const struct cl_page_slice *slice,
- int ioret)
-{
- vvp_transient_page_verify(slice->cpl_page);
+ return -EBUSY;
}
static void vvp_transient_page_fini(const struct lu_env *env,
- struct cl_page_slice *slice)
+ struct cl_page_slice *slice,
+ struct pagevec *pvec)
{
struct vvp_page *vpg = cl2vvp_page(slice);
- struct cl_page *clp = slice->cpl_page;
- struct vvp_object *clobj = cl2vvp(clp->cp_obj);
+ struct vvp_object *clobj = cl2vvp(slice->cpl_obj);
- vvp_page_fini_common(vpg);
+ vvp_page_fini_common(vpg, pvec);
atomic_dec(&clobj->vob_transient_pages);
}
static const struct cl_page_operations vvp_transient_page_ops = {
- .cpo_own = vvp_transient_page_own,
- .cpo_assume = vvp_transient_page_assume,
- .cpo_unassume = vvp_transient_page_unassume,
- .cpo_disown = vvp_transient_page_disown,
.cpo_discard = vvp_transient_page_discard,
.cpo_fini = vvp_transient_page_fini,
.cpo_is_vmlocked = vvp_transient_page_is_vmlocked,
.cpo_print = vvp_page_print,
- .io = {
- [CRT_READ] = {
- .cpo_prep = vvp_transient_page_prep,
- .cpo_completion = vvp_transient_page_completion,
- },
- [CRT_WRITE] = {
- .cpo_prep = vvp_transient_page_prep,
- .cpo_completion = vvp_transient_page_completion,
- }
- }
};
int vvp_page_init(const struct lu_env *env, struct cl_object *obj,
atomic_inc(&page->cp_ref);
SetPagePrivate(vmpage);
vmpage->private = (unsigned long)page;
- cl_page_slice_add(page, &vpg->vpg_cl, obj, index,
+ cl_page_slice_add(page, &vpg->vpg_cl, obj,
&vvp_page_ops);
} else {
struct vvp_object *clobj = cl2vvp(obj);
- cl_page_slice_add(page, &vpg->vpg_cl, obj, index,
+ cl_page_slice_add(page, &vpg->vpg_cl, obj,
&vvp_transient_page_ops);
atomic_inc(&clobj->vob_transient_pages);
}