4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (C) 2013, Trustees of Indiana University
24 * Author: Joshua Walgenbach <jjw@iu.edu>
26 #include <linux/module.h>
27 #include <lustre_net.h>
28 #include <obd_class.h>
29 #include "nodemap_internal.h"
31 #define HASH_NODEMAP_MEMBER_BKT_BITS 3
32 #define HASH_NODEMAP_MEMBER_CUR_BITS 3
33 #define HASH_NODEMAP_MEMBER_MAX_BITS 7
36 * Delete a member from a member list
38 * \param nodemap nodemap containing list
39 * \param exp export member to delete
41 void nm_member_del(struct lu_nodemap *nodemap, struct obd_export *exp)
43 mutex_lock(&nodemap->nm_member_list_lock);
44 list_del_init(&exp->exp_target_data.ted_nodemap_member);
45 mutex_unlock(&nodemap->nm_member_list_lock);
47 exp->exp_target_data.ted_nodemap = NULL;
48 class_export_put(exp);
52 * Delete a member list from a nodemap
54 * \param nodemap nodemap to remove the list from
56 void nm_member_delete_list(struct lu_nodemap *nodemap)
58 struct obd_export *exp;
59 struct obd_export *tmp;
61 mutex_lock(&nodemap->nm_member_list_lock);
62 list_for_each_entry_safe(exp, tmp, &nodemap->nm_member_list,
63 exp_target_data.ted_nodemap_member) {
64 exp->exp_target_data.ted_nodemap = NULL;
65 list_del_init(&exp->exp_target_data.ted_nodemap_member);
66 class_export_put(exp);
68 mutex_unlock(&nodemap->nm_member_list_lock);
72 * Add a member export to a nodemap
74 * \param nodemap nodemap to add to
75 * \param exp obd_export to add
76 * \retval -EEXIST export is already part of a different nodemap
77 * \retval -EINVAL export is NULL
79 int nm_member_add(struct lu_nodemap *nodemap, struct obd_export *exp)
82 CWARN("attempted to add null export to nodemap %s\n",
87 if (exp->exp_target_data.ted_nodemap != NULL &&
88 !list_empty(&exp->exp_target_data.ted_nodemap_member)) {
89 /* export is already member of nodemap */
90 if (exp->exp_target_data.ted_nodemap == nodemap)
93 /* possibly reconnecting while about to be reclassified */
94 CWARN("export %p %s already hashed, failed to add to "
95 "nodemap %s already member of %s\n", exp,
96 exp->exp_client_uuid.uuid,
98 (exp->exp_target_data.ted_nodemap == NULL) ? "unknown" :
99 exp->exp_target_data.ted_nodemap->nm_name);
103 class_export_get(exp);
104 exp->exp_target_data.ted_nodemap = nodemap;
105 mutex_lock(&nodemap->nm_member_list_lock);
106 list_add(&exp->exp_target_data.ted_nodemap_member,
107 &nodemap->nm_member_list);
108 mutex_unlock(&nodemap->nm_member_list_lock);
114 * Revokes the locks on an export if it is attached to an MDT and not in
115 * recovery. As a performance enhancement, the lock revoking process could
116 * revoke only the locks that cover files affected by the nodemap change.
118 static void nm_member_exp_revoke(struct obd_export *exp)
120 struct obd_type *type = exp->exp_obd->obd_type;
121 if (strcmp(type->typ_name, LUSTRE_MDT_NAME) != 0)
123 if (exp->exp_obd->obd_recovering)
126 ldlm_revoke_export_locks(exp);
129 /* Mutex used to serialize calls to reclassify_nodemap_lock */
130 DEFINE_MUTEX(reclassify_nodemap_lock);
133 * Reclassify the members of a nodemap after range changes or activation.
134 * This function reclassifies the members of a nodemap based on the member
135 * export's NID and the nodemap's new NID ranges. Exports that are no longer
136 * classified as being part of this nodemap are moved to the nodemap whose
137 * NID ranges contain the export's NID, and their locks are revoked.
139 * Calls to this function are serialized due to a potential deadlock: Say there
140 * is a nodemap A and a nodemap B that both need to reclassify their members.
141 * If there is a member in nodemap A that should be in nodemap B, reclassify
142 * will attempt to add the member to nodemap B. If nodemap B is also
143 * reclassifying its members, then its hash is locked and nodemap A's attempt
144 * to add will block and wait for nodemap B's reclassify to finish. If
145 * nodemap B's reclassify then attempts to reclassify a member that should be
146 * in nodemap A, it will also try add the member to nodemap A's locked hash,
147 * causing a deadlock.
149 * \param nodemap nodemap with members to reclassify
151 void nm_member_reclassify_nodemap(struct lu_nodemap *nodemap)
153 struct obd_export *exp;
154 struct obd_export *tmp;
155 struct lu_nodemap *new_nodemap;
157 /* reclassify only one nodemap at a time to avoid deadlock */
158 mutex_lock(&reclassify_nodemap_lock);
159 mutex_lock(&nodemap->nm_member_list_lock);
160 list_for_each_entry_safe(exp, tmp, &nodemap->nm_member_list,
161 exp_target_data.ted_nodemap_member) {
162 lnet_nid_t nid = exp->exp_connection->c_peer.nid;
164 /* nodemap_classify_nid requires range tree lock */
165 read_lock(&nm_range_tree_lock);
166 new_nodemap = nodemap_classify_nid(nid);
167 read_unlock(&nm_range_tree_lock);
168 if (new_nodemap != nodemap) {
169 /* don't use member_del because ted_nodemap
170 * should never be null
172 list_del_init(&exp->exp_target_data.ted_nodemap_member);
173 exp->exp_target_data.ted_nodemap = new_nodemap;
175 /* could deadlock if new_nodemap also reclassifying */
176 mutex_lock(&new_nodemap->nm_member_list_lock);
177 list_add(&exp->exp_target_data.ted_nodemap_member,
178 &new_nodemap->nm_member_list);
179 mutex_unlock(&new_nodemap->nm_member_list_lock);
180 nm_member_exp_revoke(exp);
182 nodemap_putref(new_nodemap);
184 mutex_unlock(&nodemap->nm_member_list_lock);
185 mutex_unlock(&reclassify_nodemap_lock);
189 * Revoke the locks for member exports. Changing the idmap is
190 * akin to deleting the security context. If the locks are not
191 * canceled, the client could cache permissions that are no
192 * longer correct with the map.
194 * \param nodemap nodemap that has been altered
196 void nm_member_revoke_locks(struct lu_nodemap *nodemap)
198 struct obd_export *exp;
199 struct obd_export *tmp;
201 mutex_lock(&nodemap->nm_member_list_lock);
202 list_for_each_entry_safe(exp, tmp, &nodemap->nm_member_list,
203 exp_target_data.ted_nodemap_member)
204 nm_member_exp_revoke(exp);
205 mutex_unlock(&nodemap->nm_member_list_lock);