#define HASH_NODEMAP_MEMBER_CUR_BITS 3
#define HASH_NODEMAP_MEMBER_MAX_BITS 7
+
/**
- * Delete a member from a member list
+ * Delete an export from a nodemap's member list. Called after client
+ * disconnects, or during system shutdown.
+ *
+ * Requires active_config_lock and nodemap's nm_member_list_lock.
*
* \param nodemap nodemap containing list
* \param exp export member to delete
*/
void nm_member_del(struct lu_nodemap *nodemap, struct obd_export *exp)
{
- mutex_lock(&nodemap->nm_member_list_lock);
+ ENTRY;
+
+ /* because all changes to ted_nodemap are with active_config_lock */
+ LASSERT(exp->exp_target_data.ted_nodemap == nodemap);
+
+ /* protected by nm_member_list_lock */
list_del_init(&exp->exp_target_data.ted_nodemap_member);
- mutex_unlock(&nodemap->nm_member_list_lock);
+ spin_lock(&exp->exp_target_data.ted_nodemap_lock);
exp->exp_target_data.ted_nodemap = NULL;
+ spin_unlock(&exp->exp_target_data.ted_nodemap_lock);
+
+ /* ref formerly held by ted_nodemap */
+ nodemap_putref(nodemap);
+
+ /* ref formerly held by ted_nodemap_member */
class_export_put(exp);
+
+ EXIT;
}
/**
* Delete a member list from a nodemap
*
+ * Requires active config lock.
+ *
* \param nodemap nodemap to remove the list from
*/
void nm_member_delete_list(struct lu_nodemap *nodemap)
mutex_lock(&nodemap->nm_member_list_lock);
list_for_each_entry_safe(exp, tmp, &nodemap->nm_member_list,
- exp_target_data.ted_nodemap_member) {
- exp->exp_target_data.ted_nodemap = NULL;
- list_del_init(&exp->exp_target_data.ted_nodemap_member);
- class_export_put(exp);
- }
+ exp_target_data.ted_nodemap_member)
+ nm_member_del(nodemap, exp);
mutex_unlock(&nodemap->nm_member_list_lock);
}
/**
* Add a member export to a nodemap
*
+ * Must be called under active_config_lock.
+ *
* \param nodemap nodemap to add to
* \param exp obd_export to add
* \retval -EEXIST export is already part of a different nodemap
*/
int nm_member_add(struct lu_nodemap *nodemap, struct obd_export *exp)
{
+ ENTRY;
+
if (exp == NULL) {
CWARN("attempted to add null export to nodemap %s\n",
nodemap->nm_name);
- return -EINVAL;
+ RETURN(-EINVAL);
}
+ mutex_lock(&nodemap->nm_member_list_lock);
if (exp->exp_target_data.ted_nodemap != NULL &&
!list_empty(&exp->exp_target_data.ted_nodemap_member)) {
+ mutex_unlock(&nodemap->nm_member_list_lock);
+
/* export is already member of nodemap */
if (exp->exp_target_data.ted_nodemap == nodemap)
- return 0;
+ RETURN(0);
/* possibly reconnecting while about to be reclassified */
CWARN("export %p %s already hashed, failed to add to "
nodemap->nm_name,
(exp->exp_target_data.ted_nodemap == NULL) ? "unknown" :
exp->exp_target_data.ted_nodemap->nm_name);
- return -EEXIST;
+ RETURN(-EEXIST);
}
class_export_get(exp);
+ nodemap_getref(nodemap);
+ /* ted_nodemap changes also require ac lock, member_list_lock */
+ spin_lock(&exp->exp_target_data.ted_nodemap_lock);
exp->exp_target_data.ted_nodemap = nodemap;
- mutex_lock(&nodemap->nm_member_list_lock);
+ spin_unlock(&exp->exp_target_data.ted_nodemap_lock);
list_add(&exp->exp_target_data.ted_nodemap_member,
&nodemap->nm_member_list);
mutex_unlock(&nodemap->nm_member_list_lock);
- return 0;
+ RETURN(0);
}
/**
struct obd_export *tmp;
struct lu_nodemap *new_nodemap;
+ ENTRY;
+
mutex_lock(&nodemap->nm_member_list_lock);
+
list_for_each_entry_safe(exp, tmp, &nodemap->nm_member_list,
exp_target_data.ted_nodemap_member) {
- struct ptlrpc_connection *conn = exp->exp_connection;
+ lnet_nid_t nid;
/* if no conn assigned to this exp, reconnect will reclassify */
- if (conn)
- /* nodemap_classify_nid requires nmc_range_tree_lock */
- new_nodemap = nodemap_classify_nid(conn->c_peer.nid);
- else
+ spin_lock(&exp->exp_lock);
+ if (exp->exp_connection) {
+ nid = exp->exp_connection->c_peer.nid;
+ } else {
+ spin_unlock(&exp->exp_lock);
+ continue;
+ }
+ spin_unlock(&exp->exp_lock);
+
+ /* nodemap_classify_nid requires nmc_range_tree_lock */
+ new_nodemap = nodemap_classify_nid(nid);
+ if (IS_ERR(new_nodemap))
continue;
if (new_nodemap != nodemap) {
+ /* could deadlock if new_nodemap also reclassifying,
+ * active_config_lock serializes reclassifies
+ */
+ mutex_lock(&new_nodemap->nm_member_list_lock);
+
/* don't use member_del because ted_nodemap
- * should never be null
+ * should never be NULL with a live export
*/
list_del_init(&exp->exp_target_data.ted_nodemap_member);
+
+ /* keep the new_nodemap ref from classify */
+ spin_lock(&exp->exp_target_data.ted_nodemap_lock);
exp->exp_target_data.ted_nodemap = new_nodemap;
+ spin_unlock(&exp->exp_target_data.ted_nodemap_lock);
+ nodemap_putref(nodemap);
- /* could deadlock if new_nodemap also reclassifying */
- mutex_lock(&new_nodemap->nm_member_list_lock);
list_add(&exp->exp_target_data.ted_nodemap_member,
&new_nodemap->nm_member_list);
mutex_unlock(&new_nodemap->nm_member_list_lock);
- nm_member_exp_revoke(exp);
- }
- /* This put won't destroy new_nodemap because any nodemap_del
- * call done on new_nodemap blocks on our active_config_lock
- */
- nodemap_putref(new_nodemap);
+ if (nodemap_active)
+ nm_member_exp_revoke(exp);
+ } else {
+ nodemap_putref(new_nodemap);
+ }
}
mutex_unlock(&nodemap->nm_member_list_lock);
+
+ EXIT;
}
/**
- * Revoke the locks for member exports. Changing the idmap is
- * akin to deleting the security context. If the locks are not
- * canceled, the client could cache permissions that are no
- * longer correct with the map.
+ * Revoke the locks for member exports if nodemap system is active.
+ *
+ * Changing the idmap is akin to deleting the security context. If the locks
+ * are not canceled, the client could cache permissions that are no longer
+ * correct with the map.
*
* \param nodemap nodemap that has been altered
*/
void nm_member_revoke_locks(struct lu_nodemap *nodemap)
{
+ if (!nodemap_active)
+ return;
+
+ nm_member_revoke_locks_always(nodemap);
+}
+
+void nm_member_revoke_locks_always(struct lu_nodemap *nodemap)
+{
struct obd_export *exp;
struct obd_export *tmp;