From 93fe562c5dd3829939e3bc0533918f66b19776a4 Mon Sep 17 00:00:00 2001 From: Jinshan Xiong Date: Mon, 30 Sep 2013 14:09:26 -0700 Subject: [PATCH] LU-3321 clio: revert LU-2622 for removing global env list Revert "LU-2622 obdclass: Remove the global cl_env list" This reverts commit d5390bbde9b525b13ab91f5610abe1c4bb98eff9. The performance dropped a lot when memory reclaim process kicked in as ll_releasepage() was called to destroy lustre pages. It turned out that big overhead to allocate cl_env and keys on the fly so we have to revert this patch. The problem of LU-2622 will be solved in another patch later on. Signed-off-by: Jinshan Xiong Change-Id: If5f9faeabbe78d3a88b25bf986a2c9a2ecc9ba12 Reviewed-on: http://review.whamcloud.com/7888 Tested-by: Jenkins Tested-by: Maloo Reviewed-by: Niu Yawei Reviewed-by: Lai Siyao Reviewed-by: Oleg Drokin --- lustre/include/cl_object.h | 1 + lustre/lclient/lcommon_misc.c | 3 +- lustre/liblustre/llite_cl.c | 1 + lustre/llite/llite_lib.c | 2 + lustre/obdclass/cl_object.c | 90 ++++++++++++++++++++++++++++++++++++++++--- lustre/obdclass/lu_object.c | 2 + 6 files changed, 93 insertions(+), 6 deletions(-) diff --git a/lustre/include/cl_object.h b/lustre/include/cl_object.h index 372ea82..cfaa8fc 100644 --- a/lustre/include/cl_object.h +++ b/lustre/include/cl_object.h @@ -3270,6 +3270,7 @@ void *cl_env_reenter (void); void cl_env_reexit (void *cookie); void cl_env_implant (struct lu_env *env, int *refcheck); void cl_env_unplant (struct lu_env *env, int *refcheck); +unsigned cl_env_cache_purge(unsigned nr); /** @} cl_env */ diff --git a/lustre/lclient/lcommon_misc.c b/lustre/lclient/lcommon_misc.c index d531507..2ba559e 100644 --- a/lustre/lclient/lcommon_misc.c +++ b/lustre/lclient/lcommon_misc.c @@ -142,10 +142,11 @@ int cl_get_grouplock(struct cl_object *obj, unsigned long gid, int nonblock, rc = cl_io_init(env, io, CIT_MISC, io->ci_obj); if (rc) { + cl_io_fini(env, io); + cl_env_put(env, &refcheck); /* Does not make sense to take GL for released layout */ if (rc > 0) rc = -ENOTSUPP; - cl_env_put(env, &refcheck); return rc; } diff --git a/lustre/liblustre/llite_cl.c b/lustre/liblustre/llite_cl.c index 630be49..5c7ce91 100644 --- a/lustre/liblustre/llite_cl.c +++ b/lustre/liblustre/llite_cl.c @@ -792,5 +792,6 @@ int cl_sb_fini(struct llu_sb_info *sbi) * automatically when last device is destroyed). */ lu_types_stop(); + cl_env_cache_purge(~0); RETURN(0); } diff --git a/lustre/llite/llite_lib.c b/lustre/llite/llite_lib.c index 66e72d5..4f032c3 100644 --- a/lustre/llite/llite_lib.c +++ b/lustre/llite/llite_lib.c @@ -1166,6 +1166,8 @@ void ll_put_super(struct super_block *sb) lustre_common_put_super(sb); + cl_env_cache_purge(~0); + module_put(THIS_MODULE); EXIT; diff --git a/lustre/obdclass/cl_object.c b/lustre/obdclass/cl_object.c index a7236fc..8f29926 100644 --- a/lustre/obdclass/cl_object.c +++ b/lustre/obdclass/cl_object.c @@ -533,6 +533,12 @@ EXPORT_SYMBOL(cl_site_stats_print); * bz20044, bz22683. */ +static CFS_LIST_HEAD(cl_envs); +static unsigned cl_envs_cached_nr = 0; +static unsigned cl_envs_cached_max = 128; /* XXX: prototype: arbitrary limit + * for now. */ +static DEFINE_SPINLOCK(cl_envs_guard); + struct cl_env { void *ce_magic; struct lu_env ce_lu; @@ -787,6 +793,40 @@ static void cl_env_fini(struct cl_env *cle) OBD_SLAB_FREE_PTR(cle, cl_env_kmem); } +static struct lu_env *cl_env_obtain(void *debug) +{ + struct cl_env *cle; + struct lu_env *env; + + ENTRY; + spin_lock(&cl_envs_guard); + LASSERT(equi(cl_envs_cached_nr == 0, cfs_list_empty(&cl_envs))); + if (cl_envs_cached_nr > 0) { + int rc; + + cle = container_of(cl_envs.next, struct cl_env, ce_linkage); + cfs_list_del_init(&cle->ce_linkage); + cl_envs_cached_nr--; + spin_unlock(&cl_envs_guard); + + env = &cle->ce_lu; + rc = lu_env_refill(env); + if (rc == 0) { + cl_env_init0(cle, debug); + lu_context_enter(&env->le_ctx); + lu_context_enter(&cle->ce_ses); + } else { + cl_env_fini(cle); + env = ERR_PTR(rc); + } + } else { + spin_unlock(&cl_envs_guard); + env = cl_env_new(lu_context_tags_default, + lu_session_tags_default, debug); + } + RETURN(env); +} + static inline struct cl_env *cl_env_container(struct lu_env *env) { return container_of(env, struct cl_env, ce_lu); @@ -818,6 +858,8 @@ EXPORT_SYMBOL(cl_env_peek); * Returns lu_env: if there already is an environment associated with the * current thread, it is returned, otherwise, new environment is allocated. * + * Allocations are amortized through the global cache of environments. + * * \param refcheck pointer to a counter used to detect environment leaks. In * the usual case cl_env_get() and cl_env_put() are called in the same lexical * scope and pointer to the same integer is passed as \a refcheck. This is @@ -831,10 +873,7 @@ struct lu_env *cl_env_get(int *refcheck) env = cl_env_peek(refcheck); if (env == NULL) { - env = cl_env_new(lu_context_tags_default, - lu_session_tags_default, - __builtin_return_address(0)); - + env = cl_env_obtain(__builtin_return_address(0)); if (!IS_ERR(env)) { struct cl_env *cle; @@ -878,6 +917,33 @@ static void cl_env_exit(struct cl_env *cle) } /** + * Finalizes and frees a given number of cached environments. This is done to + * (1) free some memory (not currently hooked into VM), or (2) release + * references to modules. + */ +unsigned cl_env_cache_purge(unsigned nr) +{ + struct cl_env *cle; + + ENTRY; + spin_lock(&cl_envs_guard); + for (; !cfs_list_empty(&cl_envs) && nr > 0; --nr) { + cle = container_of(cl_envs.next, struct cl_env, ce_linkage); + cfs_list_del_init(&cle->ce_linkage); + LASSERT(cl_envs_cached_nr > 0); + cl_envs_cached_nr--; + spin_unlock(&cl_envs_guard); + + cl_env_fini(cle); + spin_lock(&cl_envs_guard); + } + LASSERT(equi(cl_envs_cached_nr == 0, cfs_list_empty(&cl_envs))); + spin_unlock(&cl_envs_guard); + RETURN(nr); +} +EXPORT_SYMBOL(cl_env_cache_purge); + +/** * Release an environment. * * Decrement \a env reference counter. When counter drops to 0, nothing in @@ -899,7 +965,21 @@ void cl_env_put(struct lu_env *env, int *refcheck) cl_env_detach(cle); cle->ce_debug = NULL; cl_env_exit(cle); - cl_env_fini(cle); + /* + * Don't bother to take a lock here. + * + * Return environment to the cache only when it was allocated + * with the standard tags. + */ + if (cl_envs_cached_nr < cl_envs_cached_max && + (env->le_ctx.lc_tags & ~LCT_HAS_EXIT) == LCT_CL_THREAD && + (env->le_ses->lc_tags & ~LCT_HAS_EXIT) == LCT_SESSION) { + spin_lock(&cl_envs_guard); + cfs_list_add(&cle->ce_linkage, &cl_envs); + cl_envs_cached_nr++; + spin_unlock(&cl_envs_guard); + } else + cl_env_fini(cle); } } EXPORT_SYMBOL(cl_env_put); diff --git a/lustre/obdclass/lu_object.c b/lustre/obdclass/lu_object.c index 9842ab2..28a18ef 100644 --- a/lustre/obdclass/lu_object.c +++ b/lustre/obdclass/lu_object.c @@ -1550,11 +1550,13 @@ static CFS_LIST_HEAD(lu_context_remembered); void lu_context_key_quiesce(struct lu_context_key *key) { struct lu_context *ctx; + extern unsigned cl_env_cache_purge(unsigned nr); if (!(key->lct_tags & LCT_QUIESCENT)) { /* * XXX layering violation. */ + cl_env_cache_purge(~0); key->lct_tags |= LCT_QUIESCENT; /* * XXX memory barrier has to go here. -- 1.8.3.1