#include <linux/radix-tree.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
+#include <linux/pagevec.h>
#include <lustre_dlm.h>
struct obd_info;
const struct cl_page_slice *slice);
/** Destructor. Frees resources and slice itself. */
void (*cpo_fini)(const struct lu_env *env,
- struct cl_page_slice *slice);
+ struct cl_page_slice *slice,
+ struct pagevec *pvec);
/**
* Optional debugging helper. Prints given page slice.
*
void cl_page_get (struct cl_page *page);
void cl_page_put (const struct lu_env *env,
struct cl_page *page);
+void cl_pagevec_put (const struct lu_env *env,
+ struct cl_page *page,
+ struct pagevec *pvec);
void cl_page_print (const struct lu_env *env, void *cookie,
lu_printer_t printer,
const struct cl_page *pg);
return false;
}
+#ifdef HAVE_PAGEVEC_INIT_ONE_PARAM
+#define ll_pagevec_init(pvec, n) pagevec_init(pvec)
+#else
+#define ll_pagevec_init(pvec, n) pagevec_init(pvec, n)
+#endif
+
#endif /* _LUSTRE_COMPAT_H */
struct lustre_handle oti_handle;
struct cl_page_list oti_plist;
struct cl_io oti_io;
+ struct pagevec oti_pagevec;
void *oti_pvec[OTI_PVEC_SIZE];
/**
* Fields used by cl_lock_discard_pages().
*
*/
-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,
}
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);
- vvp_page_fini_common(vpg);
+ vvp_page_fini_common(vpg, pvec);
atomic_dec(&clobj->vob_transient_pages);
}
lov_request.o \
lovsub_dev.o \
lovsub_object.o \
- lovsub_page.o \
lproc_lov.o
EXTRA_DIST = $(lov-objs:.o=.c) lov_internal.h lov_cl_internal.h
struct cl_io *lse_io;
};
-struct lovsub_page {
- struct cl_page_slice lsb_cl;
-};
-
-
struct lov_thread_info {
struct cl_object_conf lti_stripe_conf;
struct lu_fid lti_fid;
int lov_page_init (const struct lu_env *env, struct cl_object *ob,
struct cl_page *page, pgoff_t index);
-int lovsub_page_init (const struct lu_env *env, struct cl_object *ob,
- struct cl_page *page, pgoff_t index);
int lov_page_init_empty (const struct lu_env *env, struct cl_object *obj,
struct cl_page *page, pgoff_t index);
int lov_page_init_composite(const struct lu_env *env, struct cl_object *obj,
return container_of0(slice, struct lov_page, lps_cl);
}
-static inline struct lovsub_page *
-cl2lovsub_page(const struct cl_page_slice *slice)
-{
- LINVRNT(lovsub_is_object(&slice->cpl_obj->co_lu));
- return container_of0(slice, struct lovsub_page, lsb_cl);
-}
-
static inline struct lov_io *cl2lov_io(const struct lu_env *env,
const struct cl_io_slice *ios)
{
+++ /dev/null
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.gnu.org/licenses/gpl-2.0.html
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- *
- * Copyright (c) 2013, 2014, Intel Corporation.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- *
- * Implementation of cl_page for LOVSUB layer.
- *
- * Author: Nikita Danilov <nikita.danilov@sun.com>
- */
-
-#define DEBUG_SUBSYSTEM S_LOV
-
-#include "lov_cl_internal.h"
-
-/** \addtogroup lov
- * @{
- */
-
-/*****************************************************************************
- *
- * Lovsub page operations.
- *
- */
-
-static void lovsub_page_fini(const struct lu_env *env,
- struct cl_page_slice *slice)
-{
-}
-
-static const struct cl_page_operations lovsub_page_ops = {
- .cpo_fini = lovsub_page_fini
-};
-
-int lovsub_page_init(const struct lu_env *env, struct cl_object *obj,
- struct cl_page *page, pgoff_t index)
-{
- struct lovsub_page *lsb = cl_object_page_slice(obj, page);
- ENTRY;
-
- cl_page_slice_add(page, &lsb->lsb_cl, obj, index, &lovsub_page_ops);
- RETURN(0);
-}
-
-/** @} lov */
RETURN(NULL);
}
-static void cl_page_free(const struct lu_env *env, struct cl_page *page)
+static void cl_page_free(const struct lu_env *env, struct cl_page *page,
+ struct pagevec *pvec)
{
struct cl_object *obj = page->cp_obj;
int pagesize = cl_object_header(obj)->coh_page_bufsize;
struct cl_page_slice, cpl_linkage);
list_del_init(page->cp_layers.next);
if (unlikely(slice->cpl_ops->cpo_fini != NULL))
- slice->cpl_ops->cpo_fini(env, slice);
+ slice->cpl_ops->cpo_fini(env, slice, pvec);
}
cs_page_dec(obj, CS_total);
cs_pagestate_dec(obj, page->cp_state);
ind);
if (result != 0) {
cl_page_delete0(env, page);
- cl_page_free(env, page);
+ cl_page_free(env, page, NULL);
page = ERR_PTR(result);
break;
}
EXPORT_SYMBOL(cl_page_get);
/**
- * Releases a reference to a page.
+ * Releases a reference to a page, use the pagevec to release the pages
+ * in batch if provided.
*
- * When last reference is released, page is returned to the cache, unless it
- * is in cl_page_state::CPS_FREEING state, in which case it is immediately
- * destroyed.
- *
- * \see cl_object_put(), cl_lock_put().
+ * Users need to do a final pagevec_release() to release any trailing pages.
*/
-void cl_page_put(const struct lu_env *env, struct cl_page *page)
+void cl_pagevec_put(const struct lu_env *env, struct cl_page *page,
+ struct pagevec *pvec)
{
ENTRY;
CL_PAGE_HEADER(D_TRACE, env, page, "%d\n",
* Page is no longer reachable by other threads. Tear
* it down.
*/
- cl_page_free(env, page);
+ cl_page_free(env, page, pvec);
}
EXIT;
}
+EXPORT_SYMBOL(cl_pagevec_put);
+
+/**
+ * Releases a reference to a page, wrapper to cl_pagevec_put
+ *
+ * When last reference is released, page is returned to the cache, unless it
+ * is in cl_page_state::CPS_FREEING state, in which case it is immediately
+ * destroyed.
+ *
+ * \see cl_object_put(), cl_lock_put().
+ */
+void cl_page_put(const struct lu_env *env, struct cl_page *page)
+{
+ cl_pagevec_put(env, page, NULL);
+}
EXPORT_SYMBOL(cl_page_put);
/**
}
static void echo_page_fini(const struct lu_env *env,
- struct cl_page_slice *slice)
+ struct cl_page_slice *slice,
+ struct pagevec *pvec)
{
struct echo_object *eco = cl2echo_obj(slice->cpl_obj);
ENTRY;
struct client_obd *cli = osc_cli(obj);
struct osc_async_page *oap;
struct osc_async_page *tmp;
+ struct pagevec *pvec;
int pages_in_chunk = 0;
int ppc_bits = cli->cl_chunkbits -
PAGE_SHIFT;
io = osc_env_thread_io(env);
io->ci_obj = cl_object_top(osc2cl(obj));
io->ci_ignore_layout = 1;
+ pvec = &osc_env_info(env)->oti_pagevec;
+ ll_pagevec_init(pvec, 0);
rc = cl_io_init(env, io, CIT_MISC, io->ci_obj);
if (rc < 0)
GOTO(out, rc);
}
lu_ref_del(&page->cp_reference, "truncate", current);
- cl_page_put(env, page);
+ cl_pagevec_put(env, page, pvec);
--ext->oe_nr_pages;
++nr_pages;
}
+ pagevec_release(pvec);
+
EASSERTF(ergo(ext->oe_start >= trunc_index + !!partial,
ext->oe_nr_pages == 0),
ext, "trunc_index %lu, partial %d\n", trunc_index, partial);
osc_page_gang_cbt cb, void *cbdata)
{
struct osc_page *ops;
+ struct pagevec *pagevec;
void **pvec;
pgoff_t idx;
unsigned int nr;
idx = start;
pvec = osc_env_info(env)->oti_pvec;
+ pagevec = &osc_env_info(env)->oti_pagevec;
+ ll_pagevec_init(pagevec, 0);
spin_lock(&osc->oo_tree_lock);
while ((nr = radix_tree_gang_lookup(&osc->oo_tree, pvec,
idx, OTI_PVEC_SIZE)) > 0) {
page = ops->ops_cl.cpl_page;
lu_ref_del(&page->cp_reference, "gang_lookup", current);
- cl_page_put(env, page);
+ cl_pagevec_put(env, page, pagevec);
}
+ pagevec_release(pagevec);
+
if (nr < OTI_PVEC_SIZE || end_of_region)
break;
static void discard_pagevec(const struct lu_env *env, struct cl_io *io,
struct cl_page **pvec, int max_index)
{
- int i;
+ struct pagevec *pagevec = &osc_env_info(env)->oti_pagevec;
+ int i;
- for (i = 0; i < max_index; i++) {
- struct cl_page *page = pvec[i];
+ ll_pagevec_init(pagevec, 0);
+ for (i = 0; i < max_index; i++) {
+ struct cl_page *page = pvec[i];
LASSERT(cl_page_is_owned(page, io));
cl_page_delete(env, page);
cl_page_discard(env, io, page);
cl_page_disown(env, io, page);
- cl_page_put(env, page);
+ cl_pagevec_put(env, page, pagevec);
- pvec[i] = NULL;
- }
+ pvec[i] = NULL;
+ }
+ pagevec_release(pagevec);
}
/**
struct pagevec pvec;
int i;
-#ifdef HAVE_PAGEVEC_INIT_ONE_PARAM
- pagevec_init(&pvec);
-#else
- pagevec_init(&pvec, 0);
-#endif
+ ll_pagevec_init(&pvec, 0);
for (i = 0; i < npages; i++) {
struct page *page = lnb[i].lnb_page;