goto recalc;
spin_lock(&pl->pl_lock);
- recalc_interval_sec = cfs_time_current_sec() - pl->pl_recalc_time;
if (recalc_interval_sec > 0) {
/*
* Update pool statistics every 1s.
count = pl->pl_ops->po_recalc(pl);
lprocfs_counter_add(pl->pl_stats, LDLM_POOL_RECALC_STAT,
count);
- return count;
}
+ recalc_interval_sec = pl->pl_recalc_time - cfs_time_current_sec() +
+ pl->pl_recalc_period;
- return 0;
+ return recalc_interval_sec;
}
-EXPORT_SYMBOL(ldlm_pool_recalc);
/**
* Pool shrink wrapper. Will call either client or server pool recalc callback
{
int total = 0, cached = 0, nr_ns;
struct ldlm_namespace *ns;
+ struct ldlm_namespace *ns_old = NULL; /* loop detection */
void *cookie;
if (client == LDLM_NAMESPACE_CLIENT && nr != 0 &&
/*
* Find out how many resources we may release.
*/
- for (nr_ns = cfs_atomic_read(ldlm_namespace_nr(client));
- nr_ns > 0; nr_ns--)
+ for (nr_ns = ldlm_namespace_nr_read(client);
+ nr_ns > 0; nr_ns--)
{
mutex_lock(ldlm_namespace_lock(client));
if (cfs_list_empty(ldlm_namespace_list(client))) {
return 0;
}
ns = ldlm_namespace_first_locked(client);
+
+ if (ns == ns_old) {
+ mutex_unlock(ldlm_namespace_lock(client));
+ break;
+ }
+
+ if (ldlm_ns_empty(ns)) {
+ ldlm_namespace_move_to_inactive_locked(ns, client);
+ mutex_unlock(ldlm_namespace_lock(client));
+ continue;
+ }
+
+ if (ns_old == NULL)
+ ns_old = ns;
+
ldlm_namespace_get(ns);
- ldlm_namespace_move_locked(ns, client);
+ 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);
/*
* Shrink at least ldlm_namespace_nr(client) namespaces.
*/
- for (nr_ns = cfs_atomic_read(ldlm_namespace_nr(client));
- nr_ns > 0; nr_ns--)
+ for (nr_ns = ldlm_namespace_nr_read(client) - nr_ns;
+ nr_ns > 0; nr_ns--)
{
int cancel, nr_locks;
}
ns = ldlm_namespace_first_locked(client);
ldlm_namespace_get(ns);
- ldlm_namespace_move_locked(ns, client);
+ ldlm_namespace_move_to_active_locked(ns, client);
mutex_unlock(ldlm_namespace_lock(client));
nr_locks = ldlm_pool_granted(&ns->ns_pool);
shrink_param(sc, gfp_mask));
}
-void ldlm_pools_recalc(ldlm_side_t client)
+int ldlm_pools_recalc(ldlm_side_t client)
{
__u32 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.
* for _all_ pools.
*/
l = LDLM_POOL_HOST_L /
- cfs_atomic_read(
- ldlm_namespace_nr(client));
+ ldlm_namespace_nr_read(client);
} else {
/*
* All the rest of greedy pools will have
* all locks in equal parts.
*/
l = (LDLM_POOL_HOST_L - nr_l) /
- (cfs_atomic_read(
- ldlm_namespace_nr(client)) -
+ (ldlm_namespace_nr_read(client) -
nr_p);
}
ldlm_pool_setup(&ns->ns_pool, l);
/*
* Recalc at least ldlm_namespace_nr(client) namespaces.
*/
- for (nr = cfs_atomic_read(ldlm_namespace_nr(client)); nr > 0; nr--) {
+ for (nr = ldlm_namespace_nr_read(client); nr > 0; nr--) {
int skip;
/*
* Lock the list, get first @ns in the list, getref, move it
}
ns = ldlm_namespace_first_locked(client);
+ if (ns_old == ns) { /* Full pass complete */
+ mutex_unlock(ldlm_namespace_lock(client));
+ break;
+ }
+
+ /* We got an empty namespace, need to move it back to inactive
+ * list.
+ * The race with parallel resource creation is fine:
+ * - If they do namespace_get before our check, we fail the
+ * check and they move this item to the end of the list anyway
+ * - If we do the check and then they do namespace_get, then
+ * we move the namespace to inactive and they will move
+ * it back to active (synchronised by the lock, so no clash
+ * there).
+ */
+ if (ldlm_ns_empty(ns)) {
+ ldlm_namespace_move_to_inactive_locked(ns, client);
+ mutex_unlock(ldlm_namespace_lock(client));
+ continue;
+ }
+
+ if (ns_old == NULL)
+ ns_old = ns;
+
spin_lock(&ns->ns_lock);
/*
* skip ns which is being freed, and we don't want to increase
}
spin_unlock(&ns->ns_lock);
- ldlm_namespace_move_locked(ns, client);
+ ldlm_namespace_move_to_active_locked(ns, client);
mutex_unlock(ldlm_namespace_lock(client));
- /*
- * After setup is done - recalc the pool.
- */
- if (!skip) {
- ldlm_pool_recalc(&ns->ns_pool);
- ldlm_namespace_put(ns);
- }
+ /*
+ * After setup is done - recalc the pool.
+ */
+ if (!skip) {
+ int ttime = ldlm_pool_recalc(&ns->ns_pool);
+
+ if (ttime < time)
+ time = ttime;
+
+ ldlm_namespace_put(ns);
+ }
}
+ return time;
}
EXPORT_SYMBOL(ldlm_pools_recalc);
{
struct ptlrpc_thread *thread = (struct ptlrpc_thread *)arg;
char *t_name = "ldlm_poold";
+ int s_time, c_time;
ENTRY;
cfs_daemonize(t_name);
while (1) {
struct l_wait_info lwi;
- /*
- * Recal all pools on this tick.
- */
- ldlm_pools_recalc(LDLM_NAMESPACE_SERVER);
- ldlm_pools_recalc(LDLM_NAMESPACE_CLIENT);
+ /*
+ * Recal all pools on this tick.
+ */
+ s_time = ldlm_pools_recalc(LDLM_NAMESPACE_SERVER);
+ c_time = ldlm_pools_recalc(LDLM_NAMESPACE_CLIENT);
- /*
- * Wait until the next check time, or until we're
- * stopped.
- */
- lwi = LWI_TIMEOUT(cfs_time_seconds(LDLM_POOLS_THREAD_PERIOD),
- NULL, NULL);
+ /*
+ * Wait until the next check time, or until we're
+ * stopped.
+ */
+ lwi = LWI_TIMEOUT(cfs_time_seconds(min(s_time, c_time)),
+ NULL, NULL);
l_wait_event(thread->t_ctl_waitq,
thread_is_stopping(thread) ||
thread_is_event(thread),
}
EXPORT_SYMBOL(ldlm_pools_fini);
-void ldlm_pools_recalc(ldlm_side_t client)
+int ldlm_pools_recalc(ldlm_side_t client)
{
- return;
+ return 0;
}
EXPORT_SYMBOL(ldlm_pools_recalc);
#endif /* HAVE_LRU_RESIZE_SUPPORT */