Whamcloud - gitweb
LU-5092 nodemap: convert member hash to a list
[fs/lustre-release.git] / lustre / ptlrpc / nodemap_member.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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.
9  *
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).
15  *
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
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (C) 2013, Trustees of Indiana University
24  * Author: Joshua Walgenbach <jjw@iu.edu>
25  */
26 #include <linux/module.h>
27 #include <lustre_net.h>
28 #include <obd_class.h>
29 #include "nodemap_internal.h"
30
31 #define HASH_NODEMAP_MEMBER_BKT_BITS 3
32 #define HASH_NODEMAP_MEMBER_CUR_BITS 3
33 #define HASH_NODEMAP_MEMBER_MAX_BITS 7
34
35 /**
36  * Delete a member from a member list
37  *
38  * \param       nodemap         nodemap containing list
39  * \param       exp             export member to delete
40  */
41 void nm_member_del(struct lu_nodemap *nodemap, struct obd_export *exp)
42 {
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);
46
47         exp->exp_target_data.ted_nodemap = NULL;
48         class_export_put(exp);
49 }
50
51 /**
52  * Delete a member list from a nodemap
53  *
54  * \param       nodemap         nodemap to remove the list from
55  */
56 void nm_member_delete_list(struct lu_nodemap *nodemap)
57 {
58         struct obd_export *exp;
59         struct obd_export *tmp;
60
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);
67         }
68         mutex_unlock(&nodemap->nm_member_list_lock);
69 }
70
71 /**
72  * Add a member export to a nodemap
73  *
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
78  */
79 int nm_member_add(struct lu_nodemap *nodemap, struct obd_export *exp)
80 {
81         if (exp == NULL) {
82                 CWARN("attempted to add null export to nodemap %s\n",
83                       nodemap->nm_name);
84                 return -EINVAL;
85         }
86
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)
91                         return 0;
92
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,
97                       nodemap->nm_name,
98                       (exp->exp_target_data.ted_nodemap == NULL) ? "unknown" :
99                                 exp->exp_target_data.ted_nodemap->nm_name);
100                 return -EEXIST;
101         }
102
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);
109
110         return 0;
111 }
112
113 /**
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.
117  */
118 static void nm_member_exp_revoke(struct obd_export *exp)
119 {
120         struct obd_type *type = exp->exp_obd->obd_type;
121         if (strcmp(type->typ_name, LUSTRE_MDT_NAME) != 0)
122                 return;
123         if (exp->exp_obd->obd_recovering)
124                 return;
125
126         ldlm_revoke_export_locks(exp);
127 }
128
129 /* Mutex used to serialize calls to reclassify_nodemap_lock */
130 DEFINE_MUTEX(reclassify_nodemap_lock);
131
132 /**
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.
138  *
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.
148  *
149  * \param       nodemap         nodemap with members to reclassify
150  */
151 void nm_member_reclassify_nodemap(struct lu_nodemap *nodemap)
152 {
153         struct obd_export *exp;
154         struct obd_export *tmp;
155         struct lu_nodemap *new_nodemap;
156
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;
163
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
171                          */
172                         list_del_init(&exp->exp_target_data.ted_nodemap_member);
173                         exp->exp_target_data.ted_nodemap = new_nodemap;
174
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);
181                 }
182                 nodemap_putref(new_nodemap);
183         }
184         mutex_unlock(&nodemap->nm_member_list_lock);
185         mutex_unlock(&reclassify_nodemap_lock);
186 }
187
188 /**
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.
193  *
194  * \param       nodemap         nodemap that has been altered
195  */
196 void nm_member_revoke_locks(struct lu_nodemap *nodemap)
197 {
198         struct obd_export *exp;
199         struct obd_export *tmp;
200
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);
206 }