+
+/*
+ * nid<->export hash operations
+ */
+static u32 nid_keyhash(const void *data, u32 key_len, u32 seed)
+{
+ const struct obd_export *exp = data;
+ void *key;
+
+ if (!exp->exp_connection)
+ return 0;
+
+ key = &exp->exp_connection->c_peer.nid;
+ return jhash2(key, key_len / sizeof(u32), seed);
+}
+
+/*
+ * NOTE: It is impossible to find an export that is in failed
+ * state with this function
+ */
+static int
+nid_keycmp(struct rhashtable_compare_arg *arg, const void *obj)
+{
+ const lnet_nid_t *nid = arg->key;
+ const struct obd_export *exp = obj;
+
+ if (exp->exp_connection->c_peer.nid == *nid && !exp->exp_failed)
+ return 0;
+
+ return -ESRCH;
+}
+
+static void
+nid_export_exit(void *vexport, void *data)
+{
+ struct obd_export *exp = vexport;
+
+ class_export_put(exp);
+}
+
+const struct rhashtable_params nid_hash_params = {
+ .key_len = sizeof(lnet_nid_t),
+ .head_offset = offsetof(struct obd_export, exp_nid_hash),
+ .obj_hashfn = nid_keyhash,
+ .obj_cmpfn = nid_keycmp,
+ .automatic_shrinking = true,
+};
+
+int obd_nid_add(struct obd_device *obd, struct obd_export *exp)
+{
+ int rc;
+
+ if (exp == exp->exp_obd->obd_self_export || exp->exp_hashed)
+ return 0;
+
+ class_export_get(exp);
+ rc = rhltable_insert_key(&obd->obd_nid_hash,
+ &exp->exp_connection->c_peer.nid,
+ &exp->exp_nid_hash,
+ nid_hash_params);
+ if (rc) {
+ class_export_put(exp);
+ /* map obscure error codes to -ENOMEM */
+ rc = -ENOMEM;
+ } else {
+ exp->exp_hashed = 1;
+ }
+ return rc;
+}
+EXPORT_SYMBOL(obd_nid_add);
+
+void obd_nid_del(struct obd_device *obd, struct obd_export *exp)
+{
+ int rc;
+
+ if (exp == exp->exp_obd->obd_self_export || !exp->exp_hashed)
+ return;
+
+ rc = rhltable_remove(&obd->obd_nid_hash, &exp->exp_nid_hash,
+ nid_hash_params);
+ if (rc == 0) {
+ class_export_put(exp);
+ exp->exp_hashed = 0;
+ }
+}
+EXPORT_SYMBOL(obd_nid_del);
+
+int obd_nid_export_for_each(struct obd_device *obd, lnet_nid_t nid,
+ int cb(struct obd_export *exp, void *data),
+ void *data)
+{
+ struct rhlist_head *exports, *tmp;
+ struct obd_export *exp;
+ int ret = 0;
+
+ rcu_read_lock();
+ exports = rhltable_lookup(&obd->obd_nid_hash, &nid, nid_hash_params);
+ if (!exports) {
+ ret = -ENODEV;
+ goto out_unlock;
+ }
+
+ rhl_for_each_entry_rcu(exp, tmp, exports, exp_nid_hash) {
+ if (cb(exp, data))
+ ret++;
+ }
+
+out_unlock:
+ rcu_read_unlock();
+ return ret;
+}
+EXPORT_SYMBOL(obd_nid_export_for_each);