#define refcount_set atomic_set
#define refcount_inc atomic_inc
+#define refcount_inc_not_zero atomic_inc_not_zero
#define refcount_dec atomic_dec
#define refcount_dec_and_test atomic_dec_and_test
#define refcount_read atomic_read
* @{
*/
+#include <linux/rhashtable.h>
#include <linux/workqueue.h>
#include <lprocfs_status.h>
struct work_struct exp_zombie_work;
/* Unlinked export list */
struct list_head exp_stale_list;
- struct hlist_node exp_uuid_hash; /** uuid-export hash*/
+ struct rhash_head exp_uuid_hash; /** uuid-export hash */
struct hlist_node exp_nid_hash; /** nid-export hash */
struct hlist_node exp_gen_hash; /** last_rcvd clt gen hash */
/**
* protection of other bits using _bh lock */
unsigned long obd_recovery_expired:1;
/* uuid-export hash body */
- struct cfs_hash *obd_uuid_hash;
+ struct rhashtable obd_uuid_hash;
/* nid-export hash body */
struct cfs_hash *obd_nid_hash;
/* nid stats body */
struct completion obd_kobj_unregister;
};
+int obd_uuid_add(struct obd_device *obd, struct obd_export *export);
+void obd_uuid_del(struct obd_device *obd, struct obd_export *export);
+#ifdef HAVE_SERVER_SUPPORT
+struct obd_export *obd_uuid_lookup(struct obd_device *obd,
+ struct obd_uuid *uuid);
+#endif
+
/* get/set_info keys */
#define KEY_ASYNC "async"
#define KEY_CHANGELOG_CLEAR "changelog_clear"
#define HASH_POOLS_BKT_BITS 3
#define HASH_POOLS_CUR_BITS 3
#define HASH_POOLS_MAX_BITS 7
-#define HASH_UUID_BKT_BITS 5
-#define HASH_UUID_CUR_BITS 7
-#define HASH_UUID_MAX_BITS 12
#define HASH_NID_BKT_BITS 5
#define HASH_NID_CUR_BITS 7
#define HASH_NID_MAX_BITS 12
if (obd_uuid_equals(&cluuid, &target->obd_uuid))
goto dont_check_exports;
- export = cfs_hash_lookup(target->obd_uuid_hash, &cluuid);
+ export = obd_uuid_lookup(target, &cluuid);
if (!export)
goto no_export;
* the ldlm_callback_handler. Note this sends a request RPC
* from a server (MDT) to a client (MDC), backwards of normal comms.
*/
- exp = cfs_hash_lookup(mdt2obd_dev(mdt)->obd_uuid_hash, &uuid);
+ exp = obd_uuid_lookup(mdt2obd_dev(mdt), &uuid);
if (exp == NULL || exp->exp_disconnected) {
if (exp != NULL)
class_export_put(exp);
struct obd_uuid *cluuid, bool is_self)
{
struct obd_export *export;
- struct cfs_hash *hash = NULL;
int rc = 0;
ENTRY;
export->exp_last_request_time = ktime_get_real_seconds();
spin_lock_init(&export->exp_lock);
spin_lock_init(&export->exp_rpc_lock);
- INIT_HLIST_NODE(&export->exp_uuid_hash);
INIT_HLIST_NODE(&export->exp_nid_hash);
INIT_HLIST_NODE(&export->exp_gen_hash);
spin_lock_init(&export->exp_bl_list_lock);
export->exp_client_uuid = *cluuid;
obd_init_export(export);
+ at_init(&export->exp_bl_lock_at, obd_timeout, 0);
+
+ spin_lock(&obd->obd_dev_lock);
if (!obd_uuid_equals(cluuid, &obd->obd_uuid)) {
- spin_lock(&obd->obd_dev_lock);
/* shouldn't happen, but might race */
if (obd->obd_stopping)
GOTO(exit_unlock, rc = -ENODEV);
- hash = cfs_hash_getref(obd->obd_uuid_hash);
- if (hash == NULL)
- GOTO(exit_unlock, rc = -ENODEV);
- spin_unlock(&obd->obd_dev_lock);
-
- rc = cfs_hash_add_unique(hash, cluuid, &export->exp_uuid_hash);
+ rc = obd_uuid_add(obd, export);
if (rc != 0) {
- LCONSOLE_WARN("%s: denying duplicate export for %s, %d\n",
+ LCONSOLE_WARN("%s: denying duplicate export for %s: rc = %d\n",
obd->obd_name, cluuid->uuid, rc);
- GOTO(exit_err, rc = -EALREADY);
+ GOTO(exit_unlock, rc = -EALREADY);
}
}
- at_init(&export->exp_bl_lock_at, obd_timeout, 0);
- spin_lock(&obd->obd_dev_lock);
- if (obd->obd_stopping) {
- if (hash)
- cfs_hash_del(hash, cluuid, &export->exp_uuid_hash);
- GOTO(exit_unlock, rc = -ESHUTDOWN);
- }
-
if (!is_self) {
class_incref(obd, "export", export);
list_add_tail(&export->exp_obd_chain_timed,
INIT_LIST_HEAD(&export->exp_obd_chain);
}
spin_unlock(&obd->obd_dev_lock);
- if (hash)
- cfs_hash_putref(hash);
RETURN(export);
exit_unlock:
spin_unlock(&obd->obd_dev_lock);
-exit_err:
- if (hash)
- cfs_hash_putref(hash);
class_handle_unhash(&export->exp_handle);
- LASSERT(hlist_unhashed(&export->exp_uuid_hash));
obd_destroy_export(export);
OBD_FREE_PTR(export);
return ERR_PTR(rc);
spin_lock(&exp->exp_obd->obd_dev_lock);
/* delete an uuid-export hashitem from hashtables */
- if (!hlist_unhashed(&exp->exp_uuid_hash))
- cfs_hash_del(exp->exp_obd->obd_uuid_hash,
- &exp->exp_client_uuid,
- &exp->exp_uuid_hash);
+ if (exp != exp->exp_obd->obd_self_export)
+ obd_uuid_del(exp->exp_obd, exp);
#ifdef HAVE_SERVER_SUPPORT
if (!hlist_unhashed(&exp->exp_gen_hash)) {
}
EXPORT_SYMBOL(obd_export_evict_by_nid);
+#ifdef HAVE_SERVER_SUPPORT
int obd_export_evict_by_uuid(struct obd_device *obd, const char *uuid)
{
- struct cfs_hash *uuid_hash;
struct obd_export *doomed_exp = NULL;
struct obd_uuid doomed_uuid;
int exports_evicted = 0;
spin_unlock(&obd->obd_dev_lock);
return exports_evicted;
}
- uuid_hash = obd->obd_uuid_hash;
- cfs_hash_getref(uuid_hash);
spin_unlock(&obd->obd_dev_lock);
obd_str2uuid(&doomed_uuid, uuid);
if (obd_uuid_equals(&doomed_uuid, &obd->obd_uuid)) {
CERROR("%s: can't evict myself\n", obd->obd_name);
- cfs_hash_putref(uuid_hash);
return exports_evicted;
}
- doomed_exp = cfs_hash_lookup(uuid_hash, &doomed_uuid);
-
+ doomed_exp = obd_uuid_lookup(obd, &doomed_uuid);
if (doomed_exp == NULL) {
CERROR("%s: can't disconnect %s: no exports found\n",
obd->obd_name, uuid);
obd->obd_name, doomed_exp->exp_client_uuid.uuid);
class_fail_export(doomed_exp);
class_export_put(doomed_exp);
+ obd_uuid_del(obd, doomed_exp);
exports_evicted++;
}
- cfs_hash_putref(uuid_hash);
return exports_evicted;
}
+#endif /* HAVE_SERVER_SUPPORT */
#if LUSTRE_TRACKS_LOCK_EXP_REFS
void (*class_export_dump_hook)(struct obd_export*) = NULL;
}
LPROC_SEQ_FOPS_RO(lprocfs_exp_uuid);
+#define HASH_NAME_LEN 16
+
+static void ldebugfs_rhash_seq_show(const char *name, struct rhashtable *ht,
+ struct seq_file *m)
+{
+ unsigned int max_size = ht->p.max_size ? ht->p.max_size : UINT_MAX;
+ struct bucket_table *tbl;
+ int dist[8] = { 0, };
+ int maxdep = 0;
+ int i;
+
+ rcu_read_lock();
+ tbl = rht_dereference(ht->tbl, ht);
+ for (i = 0; i < tbl->size; i++) {
+ struct rhash_head *pos;
+ int count = 0;
+
+ rht_for_each(pos, tbl, i)
+ count++;
+
+ if (count)
+ maxdep = max(maxdep, count);
+
+ dist[min(fls(count), 7)]++;
+ }
+
+ seq_printf(m, "%-*s %5d %5d %10u %d.%03d 0.300 0.750 0x%03x %7d %7d %7d ",
+ HASH_NAME_LEN, name, tbl->size, ht->p.min_size, max_size,
+ atomic_read(&ht->nelems) / tbl->size,
+ atomic_read(&ht->nelems) * 1000 / tbl->size,
+ ht->p.automatic_shrinking, 0,
+ atomic_read(&ht->nelems), maxdep);
+ rcu_read_unlock();
+
+ for (i = 0; i < 8; i++)
+ seq_printf(m, "%d%c", dist[i], (i == 7) ? '\n' : '/');
+}
+
static int
lprocfs_exp_print_hash_seq(struct cfs_hash *hs, struct cfs_hash_bd *bd,
struct hlist_node *hnode, void *cb_data)
if (obd == NULL)
return 0;
+ /* header for rhashtable state */
+ seq_printf(m, "%-*s cur min max theta t-min t-max flags rehash count maxdep distribution\n",
+ HASH_NAME_LEN, "name");
+ ldebugfs_rhash_seq_show("UUID_HASH", &obd->obd_uuid_hash, m);
+
cfs_hash_debug_header(m);
- cfs_hash_debug_str(obd->obd_uuid_hash, m);
cfs_hash_debug_str(obd->obd_nid_hash, m);
cfs_hash_debug_str(obd->obd_nid_stats_hash, m);
return 0;
#include "llog_internal.h"
-static struct cfs_hash_ops uuid_hash_ops;
static struct cfs_hash_ops nid_hash_ops;
static struct cfs_hash_ops nid_stat_hash_ops;
static struct cfs_hash_ops gen_hash_ops;
+/*
+ * uuid<->export lustre hash operations
+ */
+/*
+ * NOTE: It is impossible to find an export that is in failed
+ * state with this function
+ */
+static int
+uuid_keycmp(struct rhashtable_compare_arg *arg, const void *obj)
+{
+ const struct obd_uuid *uuid = arg->key;
+ const struct obd_export *exp = obj;
+
+ if (obd_uuid_equals(uuid, &exp->exp_client_uuid) &&
+ !exp->exp_failed)
+ return 0;
+ return -ESRCH;
+}
+
+static void
+obd_export_exit(void *vexport, void *data)
+{
+ struct obd_export *exp = vexport;
+
+ class_export_put(exp);
+}
+
+static const struct rhashtable_params uuid_hash_params = {
+ .key_len = sizeof(struct obd_uuid),
+ .key_offset = offsetof(struct obd_export, exp_client_uuid),
+ .head_offset = offsetof(struct obd_export, exp_uuid_hash),
+ .obj_cmpfn = uuid_keycmp,
+ .max_size = MAX_OBD_DEVICES,
+ .automatic_shrinking = true,
+};
+
+int obd_uuid_add(struct obd_device *obd, struct obd_export *export)
+{
+ int rc;
+
+ class_export_get(export);
+ rcu_read_lock();
+ rc = rhashtable_lookup_insert_fast(&obd->obd_uuid_hash,
+ &export->exp_uuid_hash,
+ uuid_hash_params);
+ if (rc) {
+ class_export_put(export);
+ if (rc != -EEXIST) {
+ /* map obscure error codes to -ENOMEM */
+ rc = -ENOMEM;
+ } else {
+ rc = -EALREADY;
+ }
+ }
+ rcu_read_unlock();
+
+ return rc;
+}
+EXPORT_SYMBOL(obd_uuid_add);
+
+void obd_uuid_del(struct obd_device *obd, struct obd_export *export)
+{
+ int rc;
+
+ rcu_read_lock();
+ rc = rhashtable_remove_fast(&obd->obd_uuid_hash,
+ &export->exp_uuid_hash,
+ uuid_hash_params);
+ if (!rc)
+ class_export_put(export);
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL(obd_uuid_del);
+
+#ifdef HAVE_SERVER_SUPPORT
+/* obd_uuid_lookup() is used only server side by target_handle_connect(),
+ * mdt_hsm_agent_send(), and obd_export_evict_by_uuid().
+ */
+struct obd_export *obd_uuid_lookup(struct obd_device *obd,
+ struct obd_uuid *uuid)
+{
+ struct obd_export *export = NULL;
+
+ rcu_read_lock();
+ export = rhashtable_lookup_fast(&obd->obd_uuid_hash, uuid,
+ uuid_hash_params);
+ if (export && !refcount_inc_not_zero(&export->exp_handle.h_ref))
+ export = NULL;
+ rcu_read_unlock();
+
+ return export;
+}
+EXPORT_SYMBOL(obd_uuid_lookup);
+#endif /* HAVE_SERVER_SUPPORT */
+
/*********** string parsing utils *********/
/* returns 0 if we find this key in the buffer, else 1 */
* other fns check that status, and we're not actually set up yet.
*/
obd->obd_starting = 1;
- obd->obd_uuid_hash = NULL;
obd->obd_nid_hash = NULL;
obd->obd_nid_stats_hash = NULL;
obd->obd_gen_hash = NULL;
spin_unlock(&obd->obd_dev_lock);
/* create an uuid-export lustre hash */
- obd->obd_uuid_hash = cfs_hash_create("UUID_HASH",
- HASH_UUID_CUR_BITS,
- HASH_UUID_MAX_BITS,
- HASH_UUID_BKT_BITS, 0,
- CFS_HASH_MIN_THETA,
- CFS_HASH_MAX_THETA,
- &uuid_hash_ops, CFS_HASH_DEFAULT);
- if (!obd->obd_uuid_hash)
- GOTO(err_exit, err = -ENOMEM);
+ err = rhashtable_init(&obd->obd_uuid_hash, &uuid_hash_params);
+ if (err)
+ GOTO(err_starting, err);
/* create a nid-export lustre hash */
obd->obd_nid_hash = cfs_hash_create("NID_HASH",
CFS_HASH_MAX_THETA,
&nid_hash_ops, CFS_HASH_DEFAULT);
if (!obd->obd_nid_hash)
- GOTO(err_exit, err = -ENOMEM);
+ GOTO(err_uuid_hash, err = -ENOMEM);
/* create a nid-stats lustre hash */
obd->obd_nid_stats_hash = cfs_hash_create("NID_STATS",
&nid_stat_hash_ops,
CFS_HASH_DEFAULT);
if (!obd->obd_nid_stats_hash)
- GOTO(err_exit, err = -ENOMEM);
+ GOTO(err_nid_hash, err = -ENOMEM);
/* create a client_generation-export lustre hash */
obd->obd_gen_hash = cfs_hash_create("UUID_HASH",
CFS_HASH_MAX_THETA,
&gen_hash_ops, CFS_HASH_DEFAULT);
if (!obd->obd_gen_hash)
- GOTO(err_exit, err = -ENOMEM);
+ GOTO(err_nid_stats_hash, err = -ENOMEM);
err = obd_setup(obd, lcfg);
if (err)
- GOTO(err_exit, err);
+ GOTO(err_gen_hash, err);
obd->obd_set_up = 1;
obd->obd_name, obd->obd_uuid.uuid);
RETURN(0);
-err_exit:
- if (obd->obd_uuid_hash) {
- cfs_hash_putref(obd->obd_uuid_hash);
- obd->obd_uuid_hash = NULL;
- }
- if (obd->obd_nid_hash) {
- cfs_hash_putref(obd->obd_nid_hash);
- obd->obd_nid_hash = NULL;
+
+err_gen_hash:
+ if (obd->obd_gen_hash) {
+ cfs_hash_putref(obd->obd_gen_hash);
+ obd->obd_gen_hash = NULL;
}
+err_nid_stats_hash:
if (obd->obd_nid_stats_hash) {
cfs_hash_putref(obd->obd_nid_stats_hash);
obd->obd_nid_stats_hash = NULL;
}
- if (obd->obd_gen_hash) {
- cfs_hash_putref(obd->obd_gen_hash);
- obd->obd_gen_hash = NULL;
+err_nid_hash:
+ if (obd->obd_nid_hash) {
+ cfs_hash_putref(obd->obd_nid_hash);
+ obd->obd_nid_hash = NULL;
}
+err_uuid_hash:
+ rhashtable_destroy(&obd->obd_uuid_hash);
+err_starting:
obd->obd_starting = 0;
CERROR("setup %s failed (%d)\n", obd->obd_name, err);
return err;
obd->obd_name, err);
/* destroy an uuid-export hash body */
- if (obd->obd_uuid_hash) {
- cfs_hash_putref(obd->obd_uuid_hash);
- obd->obd_uuid_hash = NULL;
- }
+ rhashtable_free_and_destroy(&obd->obd_uuid_hash, obd_export_exit,
+ NULL);
/* destroy a nid-export hash body */
if (obd->obd_nid_hash) {
EXPORT_SYMBOL(class_manual_cleanup);
/*
- * uuid<->export lustre hash operations
- */
-
-static unsigned
-uuid_hash(struct cfs_hash *hs, const void *key, unsigned mask)
-{
- return cfs_hash_djb2_hash(((struct obd_uuid *)key)->uuid,
- sizeof(((struct obd_uuid *)key)->uuid), mask);
-}
-
-static void *
-uuid_key(struct hlist_node *hnode)
-{
- struct obd_export *exp;
-
- exp = hlist_entry(hnode, struct obd_export, exp_uuid_hash);
-
- return &exp->exp_client_uuid;
-}
-
-/*
- * NOTE: It is impossible to find an export that is in failed
- * state with this function
- */
-static int
-uuid_keycmp(const void *key, struct hlist_node *hnode)
-{
- struct obd_export *exp;
-
- LASSERT(key);
- exp = hlist_entry(hnode, struct obd_export, exp_uuid_hash);
-
- return obd_uuid_equals(key, &exp->exp_client_uuid) &&
- !exp->exp_failed;
-}
-
-static void *
-uuid_export_object(struct hlist_node *hnode)
-{
- return hlist_entry(hnode, struct obd_export, exp_uuid_hash);
-}
-
-static void
-uuid_export_get(struct cfs_hash *hs, struct hlist_node *hnode)
-{
- struct obd_export *exp;
-
- exp = hlist_entry(hnode, struct obd_export, exp_uuid_hash);
- class_export_get(exp);
-}
-
-static void
-uuid_export_put_locked(struct cfs_hash *hs, struct hlist_node *hnode)
-{
- struct obd_export *exp;
-
- exp = hlist_entry(hnode, struct obd_export, exp_uuid_hash);
- class_export_put(exp);
-}
-
-static struct cfs_hash_ops uuid_hash_ops = {
- .hs_hash = uuid_hash,
- .hs_key = uuid_key,
- .hs_keycmp = uuid_keycmp,
- .hs_object = uuid_export_object,
- .hs_get = uuid_export_get,
- .hs_put_locked = uuid_export_put_locked,
-};
-
-
-/*
* nid<->export hash operations
*/
-
static unsigned
nid_hash(struct cfs_hash *hs, const void *key, unsigned mask)
{
RETURN(-ENOMEM);
}
memcpy(uuid->uuid, lwpname, strlen(lwpname));
- *exp = cfs_hash_lookup(lwp->obd_uuid_hash, uuid);
+ *exp = obd_uuid_lookup(lwp, uuid);
OBD_FREE_PTR(uuid);
}