#define DEBUG_SUBSYSTEM S_LDLM
-#ifdef __KERNEL__
-# include <lustre_dlm.h>
-#else
-# include <liblustre.h>
-#endif
-
+#include <lustre_dlm.h>
#include <cl_object.h>
-
#include <obd_class.h>
#include <obd_support.h>
#include "ldlm_internal.h"
*/
#define LDLM_POOL_SLV_SHIFT (10)
-#ifdef __KERNEL__
extern struct proc_dir_entry *ldlm_ns_proc_dir;
-#endif
static inline __u64 dru(__u64 val, __u32 shift, int round_up)
{
(t >> LDLM_POOL_GSP_STEP_SHIFT));
}
+static inline int ldlm_pool_granted(struct ldlm_pool *pl)
+{
+ return atomic_read(&pl->pl_granted);
+}
+
/**
* Recalculates next grant limit on passed \a pl.
*
int granted, grant_step, limit;
limit = ldlm_pool_get_limit(pl);
- granted = atomic_read(&pl->pl_granted);
+ granted = ldlm_pool_granted(pl);
grant_step = ldlm_pool_t2gsp(pl->pl_recalc_period);
grant_step = ((limit - granted) * grant_step) / 100;
slv = pl->pl_server_lock_volume;
grant_plan = pl->pl_grant_plan;
limit = ldlm_pool_get_limit(pl);
- granted = atomic_read(&pl->pl_granted);
+ granted = ldlm_pool_granted(pl);
round_up = granted < limit;
grant_usage = max_t(int, limit - (granted - grant_plan), 1);
{
int grant_plan = pl->pl_grant_plan;
__u64 slv = pl->pl_server_lock_volume;
- int granted = atomic_read(&pl->pl_granted);
+ int granted = ldlm_pool_granted(pl);
int grant_rate = atomic_read(&pl->pl_grant_rate);
int cancel_rate = atomic_read(&pl->pl_cancel_rate);
* locks smaller in next 10h.
*/
static int ldlm_srv_pool_shrink(struct ldlm_pool *pl,
- int nr, unsigned int gfp_mask)
+ int nr, gfp_t gfp_mask)
{
__u32 limit;
* VM is asking how many entries may be potentially freed.
*/
if (nr == 0)
- return atomic_read(&pl->pl_granted);
+ return ldlm_pool_granted(pl);
/*
* Client already canceled locks but server is already in shrinker
* and can't cancel anything. Let's catch this race.
*/
- if (atomic_read(&pl->pl_granted) == 0)
+ if (ldlm_pool_granted(pl) == 0)
RETURN(0);
spin_lock(&pl->pl_lock);
static int ldlm_cli_pool_recalc(struct ldlm_pool *pl)
{
time_t recalc_interval_sec;
+ int ret;
ENTRY;
recalc_interval_sec = cfs_time_current_sec() - pl->pl_recalc_time;
* Make sure that pool knows last SLV and Limit from obd.
*/
ldlm_cli_pool_pop_slv(pl);
-
- pl->pl_recalc_time = cfs_time_current_sec();
- lprocfs_counter_add(pl->pl_stats, LDLM_POOL_TIMING_STAT,
- recalc_interval_sec);
spin_unlock(&pl->pl_lock);
/*
* Do not cancel locks in case lru resize is disabled for this ns.
*/
if (!ns_connect_lru_resize(ldlm_pl2ns(pl)))
- RETURN(0);
+ GOTO(out, ret = 0);
/*
* In the time of canceling locks on client we do not need to maintain
* It may be called when SLV has changed much, this is why we do not
* take into account pl->pl_recalc_time here.
*/
- RETURN(ldlm_cancel_lru(ldlm_pl2ns(pl), 0, LCF_ASYNC,
- LDLM_CANCEL_LRUR));
+ ret = ldlm_cancel_lru(ldlm_pl2ns(pl), 0, LCF_ASYNC,
+ LDLM_CANCEL_LRUR);
+
+out:
+ spin_lock(&pl->pl_lock);
+ /*
+ * Time of LRU resizing might be longer than period,
+ * so update after LRU resizing rather than before it.
+ */
+ pl->pl_recalc_time = cfs_time_current_sec();
+ lprocfs_counter_add(pl->pl_stats, LDLM_POOL_TIMING_STAT,
+ recalc_interval_sec);
+ spin_unlock(&pl->pl_lock);
+ RETURN(ret);
}
/**
* passed \a pl according to \a nr and \a gfp_mask.
*/
static int ldlm_cli_pool_shrink(struct ldlm_pool *pl,
- int nr, unsigned int gfp_mask)
+ int nr, gfp_t gfp_mask)
{
struct ldlm_namespace *ns;
- int canceled = 0, unused;
+ int unused;
ns = ldlm_pl2ns(pl);
unused = ns->ns_nr_unused;
spin_unlock(&ns->ns_lock);
- if (nr) {
- canceled = ldlm_cancel_lru(ns, nr, LCF_ASYNC,
- LDLM_CANCEL_SHRINK);
- }
-#ifdef __KERNEL__
- /*
- * Return the number of potentially reclaimable locks.
- */
- return ((unused - canceled) / 100) * sysctl_vfs_cache_pressure;
-#else
- return unused - canceled;
-#endif
+ if (nr == 0)
+ return (unused / 100) * sysctl_vfs_cache_pressure;
+ else
+ return ldlm_cancel_lru(ns, nr, LCF_ASYNC, LDLM_CANCEL_SHRINK);
}
struct ldlm_pool_ops ldlm_srv_pool_ops = {
}
recalc_interval_sec = pl->pl_recalc_time - cfs_time_current_sec() +
pl->pl_recalc_period;
+ if (recalc_interval_sec <= 0) {
+ /* Prevent too frequent recalculation. */
+ recalc_interval_sec = 1;
+ }
return recalc_interval_sec;
}
* Pool shrink wrapper. Will call either client or server pool recalc callback
* depending what pool \a pl is used.
*/
-int ldlm_pool_shrink(struct ldlm_pool *pl, int nr,
- unsigned int gfp_mask)
+int ldlm_pool_shrink(struct ldlm_pool *pl, int nr, gfp_t gfp_mask)
{
int cancel = 0;
}
EXPORT_SYMBOL(ldlm_pool_setup);
-#ifdef __KERNEL__
static int lprocfs_pool_state_seq_show(struct seq_file *m, void *unused)
{
int granted, grant_rate, cancel_rate, grant_step;
clv = pl->pl_client_lock_volume;
limit = ldlm_pool_get_limit(pl);
grant_plan = pl->pl_grant_plan;
- granted = atomic_read(&pl->pl_granted);
+ granted = ldlm_pool_granted(pl);
grant_rate = atomic_read(&pl->pl_grant_rate);
cancel_rate = atomic_read(&pl->pl_cancel_rate);
grant_speed = grant_rate - cancel_rate;
LDLM_POOL_PROC_READER_SEQ_SHOW(recalc_period, int);
LDLM_POOL_PROC_WRITER(recalc_period, int);
-static ssize_t lprocfs_recalc_period_seq_write(struct file *file, const char *buf,
+static ssize_t lprocfs_recalc_period_seq_write(struct file *file,
+ const char __user *buf,
size_t len, loff_t *off)
{
struct seq_file *seq = file->private_data;
pl->pl_proc_dir = NULL;
}
}
-#else /* !__KERNEL__*/
-#define ldlm_pool_proc_init(pl) (0)
-#define ldlm_pool_proc_fini(pl) while (0) {}
-#endif
int ldlm_pool_init(struct ldlm_pool *pl, struct ldlm_namespace *ns,
int idx, ldlm_side_t client)
}
EXPORT_SYMBOL(ldlm_pool_get_lvf);
-#ifdef __KERNEL__
-static unsigned int ldlm_pool_granted(struct ldlm_pool *pl)
-{
- return atomic_read(&pl->pl_granted);
-}
-
static struct ptlrpc_thread *ldlm_pools_thread;
static struct shrinker *ldlm_pools_srv_shrinker;
static struct shrinker *ldlm_pools_cli_shrinker;
static struct completion ldlm_pools_comp;
/*
- * Cancel \a nr locks from all namespaces (if possible). Returns number of
- * cached locks after shrink is finished. All namespaces are asked to
- * cancel approximately equal amount of locks to keep balancing.
- */
-static int ldlm_pools_shrink(ldlm_side_t client, int nr,
- unsigned int gfp_mask)
+* count locks from all namespaces (if possible). Returns number of
+* cached locks.
+*/
+static unsigned long ldlm_pools_count(ldlm_side_t client, gfp_t gfp_mask)
{
- unsigned int total = 0, cached = 0;
+ unsigned long total = 0;
int nr_ns;
- struct ldlm_namespace *ns;
+ struct ldlm_namespace *ns;
struct ldlm_namespace *ns_old = NULL; /* loop detection */
- void *cookie;
+ void *cookie;
- if (client == LDLM_NAMESPACE_CLIENT && nr != 0 &&
- !(gfp_mask & __GFP_FS))
- return -1;
+ if (client == LDLM_NAMESPACE_CLIENT && !(gfp_mask & __GFP_FS))
+ return 0;
- CDEBUG(D_DLMTRACE, "Request to shrink %d %s locks from all pools\n",
- nr, client == LDLM_NAMESPACE_CLIENT ? "client" : "server");
+ CDEBUG(D_DLMTRACE, "Request to count %s locks from all pools\n",
+ client == LDLM_NAMESPACE_CLIENT ? "client" : "server");
- cookie = cl_env_reenter();
+ cookie = cl_env_reenter();
- /*
- * Find out how many resources we may release.
- */
+ /*
+ * Find out how many resources we may release.
+ */
for (nr_ns = ldlm_namespace_nr_read(client);
- nr_ns > 0; nr_ns--)
- {
+ nr_ns > 0; nr_ns--) {
mutex_lock(ldlm_namespace_lock(client));
- if (cfs_list_empty(ldlm_namespace_list(client))) {
+ if (list_empty(ldlm_namespace_list(client))) {
mutex_unlock(ldlm_namespace_lock(client));
- cl_env_reexit(cookie);
- return 0;
- }
- ns = ldlm_namespace_first_locked(client);
+ cl_env_reexit(cookie);
+ return 0;
+ }
+ ns = ldlm_namespace_first_locked(client);
if (ns == ns_old) {
mutex_unlock(ldlm_namespace_lock(client));
if (ns_old == NULL)
ns_old = ns;
- ldlm_namespace_get(ns);
- ldlm_namespace_move_to_active_locked(ns, client);
+ ldlm_namespace_get(ns);
+ ldlm_namespace_move_to_active_locked(ns, client);
mutex_unlock(ldlm_namespace_lock(client));
- total += ldlm_pool_shrink(&ns->ns_pool, 0, gfp_mask);
- ldlm_namespace_put(ns);
- }
+ total += ldlm_pool_shrink(&ns->ns_pool, 0, gfp_mask);
+ ldlm_namespace_put(ns);
+ }
- if (nr == 0 || total == 0) {
- cl_env_reexit(cookie);
- return total;
- }
+ cl_env_reexit(cookie);
+ return total;
+}
- /*
- * Shrink at least ldlm_namespace_nr(client) namespaces.
- */
- for (nr_ns = ldlm_namespace_nr_read(client) - nr_ns;
- nr_ns > 0; nr_ns--)
- {
- __u64 cancel;
- unsigned int nr_locks;
+static unsigned long ldlm_pools_scan(ldlm_side_t client, int nr,
+ gfp_t gfp_mask)
+{
+ unsigned long freed = 0;
+ int tmp, nr_ns;
+ struct ldlm_namespace *ns;
+ void *cookie;
- /*
- * Do not call shrink under ldlm_namespace_lock(client)
- */
+ if (client == LDLM_NAMESPACE_CLIENT && !(gfp_mask & __GFP_FS))
+ return -1;
+
+ cookie = cl_env_reenter();
+
+ /*
+ * Shrink at least ldlm_namespace_nr_read(client) namespaces.
+ */
+ for (tmp = nr_ns = ldlm_namespace_nr_read(client);
+ tmp > 0; tmp--) {
+ int cancel, nr_locks;
+
+ /*
+ * Do not call shrink under ldlm_namespace_lock(client)
+ */
mutex_lock(ldlm_namespace_lock(client));
- if (cfs_list_empty(ldlm_namespace_list(client))) {
+ if (list_empty(ldlm_namespace_list(client))) {
mutex_unlock(ldlm_namespace_lock(client));
- /*
- * If list is empty, we can't return any @cached > 0,
- * that probably would cause needless shrinker
- * call.
- */
- cached = 0;
- break;
- }
- ns = ldlm_namespace_first_locked(client);
- ldlm_namespace_get(ns);
- ldlm_namespace_move_to_active_locked(ns, client);
+ break;
+ }
+ ns = ldlm_namespace_first_locked(client);
+ ldlm_namespace_get(ns);
+ ldlm_namespace_move_to_active_locked(ns, client);
mutex_unlock(ldlm_namespace_lock(client));
- nr_locks = ldlm_pool_granted(&ns->ns_pool);
- cancel = (__u64)nr_locks * nr;
- do_div(cancel, total);
- ldlm_pool_shrink(&ns->ns_pool, 1 + cancel, gfp_mask);
- cached += ldlm_pool_granted(&ns->ns_pool);
- ldlm_namespace_put(ns);
- }
- cl_env_reexit(cookie);
- /* we only decrease the SLV in server pools shrinker, return -1 to
- * kernel to avoid needless loop. LU-1128 */
- return (client == LDLM_NAMESPACE_SERVER) ? -1 : cached;
+ nr_locks = ldlm_pool_granted(&ns->ns_pool);
+ /*
+ * We use to shrink propotionally but with new shrinker API,
+ * we lost the total number of freeable locks.
+ */
+ cancel = 1 + min_t(int, nr_locks, nr / nr_ns);
+ freed += ldlm_pool_shrink(&ns->ns_pool, cancel, gfp_mask);
+ ldlm_namespace_put(ns);
+ }
+ cl_env_reexit(cookie);
+ /*
+ * we only decrease the SLV in server pools shrinker, return
+ * SHRINK_STOP to kernel to avoid needless loop. LU-1128
+ */
+ return (client == LDLM_NAMESPACE_SERVER) ? SHRINK_STOP : freed;
+}
+
+#ifdef HAVE_SHRINKER_COUNT
+static unsigned long ldlm_pools_srv_count(struct shrinker *s,
+ struct shrink_control *sc)
+{
+ return ldlm_pools_count(LDLM_NAMESPACE_SERVER, sc->gfp_mask);
+}
+
+static unsigned long ldlm_pools_srv_scan(struct shrinker *s,
+ struct shrink_control *sc)
+{
+ return ldlm_pools_scan(LDLM_NAMESPACE_SERVER, sc->nr_to_scan,
+ sc->gfp_mask);
+}
+
+static unsigned long ldlm_pools_cli_count(struct shrinker *s, struct shrink_control *sc)
+{
+ return ldlm_pools_count(LDLM_NAMESPACE_CLIENT, sc->gfp_mask);
+}
+
+static unsigned long ldlm_pools_cli_scan(struct shrinker *s,
+ struct shrink_control *sc)
+{
+ return ldlm_pools_scan(LDLM_NAMESPACE_CLIENT, sc->nr_to_scan,
+ sc->gfp_mask);
+}
+
+#else
+/*
+ * Cancel \a nr locks from all namespaces (if possible). Returns number of
+ * cached locks after shrink is finished. All namespaces are asked to
+ * cancel approximately equal amount of locks to keep balancing.
+ */
+static int ldlm_pools_shrink(ldlm_side_t client, int nr,
+ gfp_t gfp_mask)
+{
+ unsigned long total = 0;
+
+ if (client == LDLM_NAMESPACE_CLIENT && nr != 0 &&
+ !(gfp_mask & __GFP_FS))
+ return -1;
+
+ CDEBUG(D_DLMTRACE, "Request to shrink %d %s locks from all pools\n",
+ nr, client == LDLM_NAMESPACE_CLIENT ? "client" : "server");
+
+ total = ldlm_pools_count(client, gfp_mask);
+
+ if (nr == 0 || total == 0)
+ return total;
+
+ return ldlm_pools_scan(client, nr, gfp_mask);
}
static int ldlm_pools_srv_shrink(SHRINKER_ARGS(sc, nr_to_scan, gfp_mask))
shrink_param(sc, gfp_mask));
}
+#endif /* HAVE_SHRINKER_COUNT */
+
int ldlm_pools_recalc(ldlm_side_t client)
{
- __u32 nr_l = 0, nr_p = 0, l;
+ unsigned long nr_l = 0, nr_p = 0, l;
struct ldlm_namespace *ns;
struct ldlm_namespace *ns_old = NULL;
int nr, equal = 0;
int time = 50; /* seconds of sleep if no active namespaces */
- /*
- * No need to setup pool limit for client pools.
- */
- if (client == LDLM_NAMESPACE_SERVER) {
- /*
- * Check all modest namespaces first.
- */
+ /*
+ * No need to setup pool limit for client pools.
+ */
+ if (client == LDLM_NAMESPACE_SERVER) {
+ /*
+ * Check all modest namespaces first.
+ */
mutex_lock(ldlm_namespace_lock(client));
- cfs_list_for_each_entry(ns, ldlm_namespace_list(client),
- ns_list_chain)
- {
- if (ns->ns_appetite != LDLM_NAMESPACE_MODEST)
- continue;
+ list_for_each_entry(ns, ldlm_namespace_list(client),
+ ns_list_chain)
+ {
+ if (ns->ns_appetite != LDLM_NAMESPACE_MODEST)
+ continue;
l = ldlm_pool_granted(&ns->ns_pool);
if (l == 0)
*/
if (nr_l >= 2 * (LDLM_POOL_HOST_L / 3)) {
CWARN("\"Modest\" pools eat out 2/3 of server locks "
- "limit (%d of %lu). This means that you have too "
+ "limit (%lu of %lu). This means that you have too "
"many clients for this amount of server RAM. "
"Upgrade server!\n", nr_l, LDLM_POOL_HOST_L);
equal = 1;
}
- /*
- * The rest is given to greedy namespaces.
- */
- cfs_list_for_each_entry(ns, ldlm_namespace_list(client),
- ns_list_chain)
- {
- if (!equal && ns->ns_appetite != LDLM_NAMESPACE_GREEDY)
- continue;
+ /*
+ * The rest is given to greedy namespaces.
+ */
+ list_for_each_entry(ns, ldlm_namespace_list(client),
+ ns_list_chain)
+ {
+ if (!equal && ns->ns_appetite != LDLM_NAMESPACE_GREEDY)
+ continue;
if (equal) {
/*
* locks synchronously.
*/
mutex_lock(ldlm_namespace_lock(client));
- if (cfs_list_empty(ldlm_namespace_list(client))) {
+ if (list_empty(ldlm_namespace_list(client))) {
mutex_unlock(ldlm_namespace_lock(client));
break;
}
int ldlm_pools_init(void)
{
int rc;
+ DEF_SHRINKER_VAR(shsvar, ldlm_pools_srv_shrink,
+ ldlm_pools_srv_count, ldlm_pools_srv_scan);
+ DEF_SHRINKER_VAR(shcvar, ldlm_pools_cli_shrink,
+ ldlm_pools_cli_count, ldlm_pools_cli_scan);
ENTRY;
rc = ldlm_pools_thread_start();
if (rc == 0) {
ldlm_pools_srv_shrinker =
- set_shrinker(DEFAULT_SEEKS,
- ldlm_pools_srv_shrink);
+ set_shrinker(DEFAULT_SEEKS, &shsvar);
ldlm_pools_cli_shrinker =
- set_shrinker(DEFAULT_SEEKS,
- ldlm_pools_cli_shrink);
+ set_shrinker(DEFAULT_SEEKS, &shcvar);
}
RETURN(rc);
}
ldlm_pools_thread_stop();
}
EXPORT_SYMBOL(ldlm_pools_fini);
-#endif /* __KERNEL__ */
#else /* !HAVE_LRU_RESIZE_SUPPORT */
int ldlm_pool_setup(struct ldlm_pool *pl, int limit)
EXPORT_SYMBOL(ldlm_pool_recalc);
int ldlm_pool_shrink(struct ldlm_pool *pl,
- int nr, unsigned int gfp_mask)
+ int nr, gfp_t gfp_mask)
{
return 0;
}