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 * member hash functions
38 * The purpose of this hash is to maintain the list of
39 * exports that are connected and associated with a
42 static void nm_member_getref(struct obd_export *exp)
46 void nm_member_putref(struct obd_export *exp)
50 static __u32 nm_member_hashfn(cfs_hash_t *hash_body,
51 const void *key, unsigned mask)
53 return hash_long((unsigned long)key, hash_body->hs_bkt_bits) & mask;
56 static void *nm_member_hs_key(struct hlist_node *hnode)
58 struct obd_export *exp;
60 exp = hlist_entry(hnode, struct obd_export,
61 exp_target_data.ted_nodemap_member);
66 static int nm_member_hs_keycmp(const void *key, struct hlist_node *hnode)
68 struct obd_export *exp;
70 exp = hlist_entry(hnode, struct obd_export,
71 exp_target_data.ted_nodemap_member);
76 static void *nm_member_hs_hashobject(struct hlist_node *hnode)
78 return hlist_entry(hnode, struct obd_export,
79 exp_target_data.ted_nodemap_member);
82 static void nm_member_hs_get(cfs_hash_t *hs, struct hlist_node *hnode)
84 struct obd_export *exp;
86 exp = hlist_entry(hnode, struct obd_export,
87 exp_target_data.ted_nodemap_member);
88 nm_member_getref(exp);
91 static void nm_member_hs_put_locked(cfs_hash_t *hs,
92 struct hlist_node *hnode)
94 struct obd_export *exp;
96 exp = hlist_entry(hnode, struct obd_export,
97 exp_target_data.ted_nodemap_member);
98 nm_member_putref(exp);
102 * Delete a member from a member hash
104 * \param nodemap nodemap containing hash
105 * \paraa nid nid of member to delete
107 void nm_member_del(struct lu_nodemap *nodemap, struct obd_export *exp)
109 struct obd_export *exp1;
111 exp1 = cfs_hash_del_key(nodemap->nm_member_hash, exp);
113 class_export_put(exp1);
115 LASSERT(hlist_unhashed(&exp->exp_target_data.ted_nodemap_member));
116 exp->exp_target_data.ted_nodemap = NULL;
119 static cfs_hash_ops_t nm_member_hash_operations = {
120 .hs_hash = nm_member_hashfn,
121 .hs_key = nm_member_hs_key,
122 .hs_keycmp = nm_member_hs_keycmp,
123 .hs_object = nm_member_hs_hashobject,
124 .hs_get = nm_member_hs_get,
125 .hs_put_locked = nm_member_hs_put_locked,
129 * Init a member hash of a nodemap
131 * \param nodemap nodemap containing the member hash
133 int nm_member_init_hash(struct lu_nodemap *nodemap)
135 char nodemap_hashname[LUSTRE_NODEMAP_NAME_LENGTH + 3];
138 snprintf(nodemap_hashname, sizeof(nodemap_hashname),
139 "nm-%s", nodemap->nm_name);
140 nodemap->nm_member_hash = cfs_hash_create(nodemap_hashname,
141 HASH_NODEMAP_MEMBER_CUR_BITS,
142 HASH_NODEMAP_MEMBER_MAX_BITS,
143 HASH_NODEMAP_MEMBER_BKT_BITS, 0,
146 &nm_member_hash_operations,
148 if (nodemap->nm_member_hash == NULL)
155 * Callback from deleting a hash member
157 static int nm_member_delete_hash_cb(cfs_hash_t *hs, cfs_hash_bd_t *bd,
158 struct hlist_node *hnode, void *data)
160 struct obd_export *exp;
162 exp = hlist_entry(hnode, struct obd_export,
163 exp_target_data.ted_nodemap_member);
165 exp->exp_target_data.ted_nodemap = NULL;
166 cfs_hash_bd_del_locked(hs, bd, hnode);
167 class_export_put(exp);
173 * Delete a member hash from a nodemap
175 * \param nodemap nodemap to remove the hash from
177 void nm_member_delete_hash(struct lu_nodemap *nodemap)
179 cfs_hash_for_each_safe(nodemap->nm_member_hash,
180 nm_member_delete_hash_cb,
182 cfs_hash_putref(nodemap->nm_member_hash);
186 * Add a member export to a nodemap
188 * \param nodemap nodemap to search
189 * \param exp obd_export to search
190 * \retval -EEXIST export is already hashed to a different nodemap
191 * \retval -EINVAL export is NULL
193 int nm_member_add(struct lu_nodemap *nodemap, struct obd_export *exp)
198 CWARN("attempted to add null export to nodemap %s\n",
203 if (hlist_unhashed(&exp->exp_target_data.ted_nodemap_member) == 0) {
204 /* export is already member of nodemap */
205 if (exp->exp_target_data.ted_nodemap == nodemap)
208 /* possibly reconnecting while about to be reclassified */
209 CWARN("export %p %s already hashed, failed to add to "
210 "nodemap %s already member of %s\n", exp,
211 exp->exp_client_uuid.uuid,
213 (exp->exp_target_data.ted_nodemap == NULL) ? "unknown" :
214 exp->exp_target_data.ted_nodemap->nm_name);
218 exp->exp_target_data.ted_nodemap = nodemap;
220 rc = cfs_hash_add_unique(nodemap->nm_member_hash, exp,
221 &exp->exp_target_data.ted_nodemap_member);
224 class_export_get(exp);
225 /* else -EALREADY - exp already in nodemap hash */
231 * Revokes the locks on an export if it is attached to an MDT and not in
232 * recovery. As a performance enhancement, the lock revoking process could
233 * revoke only the locks that cover files affected by the nodemap change.
235 static void nm_member_exp_revoke(struct obd_export *exp)
237 struct obd_type *type = exp->exp_obd->obd_type;
238 if (strcmp(type->typ_name, LUSTRE_MDT_NAME) != 0)
240 if (exp->exp_obd->obd_recovering)
243 ldlm_revoke_export_locks(exp);
246 static int nm_member_reclassify_cb(cfs_hash_t *hs, cfs_hash_bd_t *bd,
247 struct hlist_node *hnode, void *data)
249 struct obd_export *exp;
250 struct lu_nodemap *nodemap;
252 exp = hlist_entry(hnode, struct obd_export,
253 exp_target_data.ted_nodemap_member);
257 /* Must use bd_del_locked inside a cfs_hash callback, and exp->nodemap
258 * should never be NULL. For those reasons, can't use member_del.
260 read_lock(&nm_range_tree_lock);
261 nodemap = nodemap_classify_nid(exp->exp_connection->c_peer.nid);
262 if (exp->exp_target_data.ted_nodemap != nodemap) {
263 cfs_hash_bd_del_locked(hs, bd, hnode);
264 exp->exp_target_data.ted_nodemap = nodemap;
265 cfs_hash_add_unique(nodemap->nm_member_hash, exp,
266 &exp->exp_target_data.ted_nodemap_member);
268 read_unlock(&nm_range_tree_lock);
270 nm_member_exp_revoke(exp);
275 DEFINE_MUTEX(reclassify_nodemap_lock);
278 * Reclassify the members of a nodemap after range changes or activation,
279 * based on the member export's NID and the nodemap's new NID ranges. Exports
280 * that are no longer classified as being part of this nodemap are moved to the
281 * nodemap whose NID ranges contain the export's NID, and their locks are
284 * \param nodemap nodemap with members to reclassify
286 void nm_member_reclassify_nodemap(struct lu_nodemap *nodemap)
288 /* reclassify only one nodemap at a time to avoid deadlock */
289 mutex_lock(&reclassify_nodemap_lock);
290 cfs_hash_for_each_safe(nodemap->nm_member_hash,
291 nm_member_reclassify_cb,
293 mutex_unlock(&reclassify_nodemap_lock);
296 static int nm_member_revoke_locks_cb(cfs_hash_t *hs, cfs_hash_bd_t *bd,
297 struct hlist_node *hnode, void *data)
299 struct obd_export *exp;
300 exp = hlist_entry(hnode, struct obd_export,
301 exp_target_data.ted_nodemap_member);
305 nm_member_exp_revoke(exp);
310 * Revoke the locks for member exports. Changing the idmap is
311 * akin to deleting the security context. If the locks are not
312 * canceled, the client could cache permissions that are no
313 * longer correct with the map.
315 * \param nodemap nodemap that has been altered
317 void nm_member_revoke_locks(struct lu_nodemap *nodemap)
319 cfs_hash_for_each(nodemap->nm_member_hash, nm_member_revoke_locks_cb,