Whamcloud - gitweb
LU-17744 ldiskfs: mballoc stats fixes
[fs/lustre-release.git] / lustre / ptlrpc / nodemap_range.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
27 #include <lustre_net.h>
28 #include "nodemap_internal.h"
29 #include <linux/interval_tree_generic.h>
30
31 /*
32  * Range trees
33  *
34  * To classify clients when they connect, build a global range tree
35  * containing all admin defined ranges. Incoming clients can then be
36  * classified into their nodemaps, and the lu_nodemap structure will be
37  * set in the export structure for the connecting client. Pointers to
38  * the lu_nid_range nodes will be added to linked links within the
39  * lu_nodemap structure for reporting purposes. Access to range tree should be
40  * controlled to prevent read access during update operations.
41  */
42
43 #define START(node)     (lnet_nid_to_nid4(&((node)->rn_start)))
44 #define LAST(node)      (lnet_nid_to_nid4(&((node)->rn_end)))
45
46 INTERVAL_TREE_DEFINE(struct lu_nid_range, rn_rb, lnet_nid_t, rn_subtree_last,
47                      START, LAST, static, nm_range)
48
49 /*
50  * range constructor
51  *
52  * \param       min             starting nid of the range
53  * \param       max             ending nid of the range
54  * \param       nodemap         nodemap that contains this range
55  * \retval      lu_nid_range on success, NULL on failure
56  */
57 struct lu_nid_range *range_create(struct nodemap_config *config,
58                                   const struct lnet_nid *start_nid,
59                                   const struct lnet_nid *end_nid,
60                                   u8 netmask, struct lu_nodemap *nodemap,
61                                   unsigned int range_id)
62 {
63         struct nodemap_range_tree *nm_range_tree;
64         struct lu_nid_range *range;
65
66         if (LNET_NID_NET(start_nid) != LNET_NID_NET(end_nid))
67                 return NULL;
68
69         if (!netmask) {
70                 lnet_nid_t nid4[2] = {
71                         lnet_nid_to_nid4(start_nid),
72                         lnet_nid_to_nid4(end_nid)
73                 };
74
75                 if (LNET_NIDADDR(nid4[0]) > LNET_NIDADDR(nid4[1]))
76                         return NULL;
77         } else if (!nid_same(start_nid, end_nid)) {
78                 /* FIXME Currently we only support one large NID per nodemap */
79                 return NULL;
80         }
81
82         OBD_ALLOC_PTR(range);
83         if (range == NULL) {
84                 CERROR("cannot allocate lu_nid_range of size %zu bytes\n",
85                        sizeof(*range));
86                 return NULL;
87         }
88
89         /* if we are loading from save, use on disk id num */
90         nm_range_tree = &config->nmc_range_tree;
91         if (range_id != 0) {
92                 if (nm_range_tree->nmrt_range_highest_id < range_id)
93                         nm_range_tree->nmrt_range_highest_id = range_id;
94                 range->rn_id = range_id;
95         } else {
96                 nm_range_tree->nmrt_range_highest_id++;
97                 range->rn_id = nm_range_tree->nmrt_range_highest_id;
98         }
99         range->rn_nodemap = nodemap;
100
101         range->rn_netmask = netmask;
102         range->rn_start = *start_nid;
103         range->rn_end = *end_nid;
104
105         INIT_LIST_HEAD(&range->rn_list);
106
107         return range;
108 }
109
110 /*
111  * find the exact range
112  *
113  * \param       start_nid               starting nid
114  * \param       end_nid                 ending nid
115  * \retval      matching range or NULL
116  */
117 struct lu_nid_range *range_find(struct nodemap_config *config,
118                                 const struct lnet_nid *start_nid,
119                                 const struct lnet_nid *end_nid,
120                                 u8 netmask)
121 {
122         struct lu_nid_range *range = NULL;
123
124         if (!netmask) {
125                 struct nodemap_range_tree *nm_range_tree;
126                 lnet_nid_t nid4[2];
127
128                 if (!nid_is_nid4(start_nid) || !nid_is_nid4(end_nid))
129                         return NULL;
130
131                 nid4[0] = lnet_nid_to_nid4(start_nid);
132                 nid4[1] = lnet_nid_to_nid4(end_nid);
133                 nm_range_tree = &config->nmc_range_tree;
134                 range = nm_range_iter_first(&nm_range_tree->nmrt_range_interval_root,
135                                             nid4[0], nid4[1]);
136                 while (range &&
137                        (!nid_same(&range->rn_start, start_nid) ||
138                         !nid_same(&range->rn_end, end_nid)))
139                         range = nm_range_iter_next(range, nid4[0], nid4[1]);
140         } else if (!list_empty(&config->nmc_netmask_setup)) {
141                 struct lu_nid_range *range_temp;
142
143                 /* FIXME. We scan the config for large NIDs. Each range
144                  * only contains one large NID for now.
145                  */
146                 list_for_each_entry_safe(range, range_temp,
147                                          &config->nmc_netmask_setup,
148                                          rn_collect) {
149                         if (nid_same(&range->rn_start, start_nid) &&
150                             range->rn_netmask == netmask)
151                                 break;
152                         range = NULL;
153                 }
154         }
155         return range;
156 }
157
158 /*
159  * range destructor
160  */
161 void range_destroy(struct lu_nid_range *range)
162 {
163         LASSERT(list_empty(&range->rn_list) == 0);
164
165         OBD_FREE_PTR(range);
166 }
167
168 /*
169  * insert an nid range into the interval tree
170  *
171  * \param       range           range to insetr
172  * \retval      0 on success
173  *
174  * This function checks that the given nid range
175  * does not overlap so that each nid can belong
176  * to exactly one range
177  */
178 int range_insert(struct nodemap_config *config, struct lu_nid_range *range)
179 {
180         if (!range->rn_netmask) {
181                 struct nodemap_range_tree *nm_range_tree;
182
183                 nm_range_tree = &config->nmc_range_tree;
184                 if (nm_range_iter_first(&nm_range_tree->nmrt_range_interval_root,
185                                         lnet_nid_to_nid4(&range->rn_start),
186                                         lnet_nid_to_nid4(&range->rn_end)))
187                         return -EEXIST;
188
189                 nm_range_insert(range,
190                                 &nm_range_tree->nmrt_range_interval_root);
191         } else {
192                 list_add(&range->rn_collect, &config->nmc_netmask_setup);
193         }
194         return 0;
195 }
196
197 /*
198  * delete a range from the interval tree and any
199  * associated nodemap references
200  *
201  * \param       range           range to remove
202  */
203 void range_delete(struct nodemap_config *config, struct lu_nid_range *range)
204 {
205         list_del(&range->rn_list);
206         if (!range->rn_netmask) {
207                 struct nodemap_range_tree *nm_range_tree;
208
209                 nm_range_tree = &config->nmc_range_tree;
210                 nm_range_remove(range,
211                                 &nm_range_tree->nmrt_range_interval_root);
212         } else {
213                 list_del(&range->rn_collect);
214         }
215         range_destroy(range);
216 }
217
218 /*
219  * search the interval tree for an nid within a range
220  *
221  * \param       nid             nid to search for
222  */
223 struct lu_nid_range *range_search(struct nodemap_config *config,
224                                   struct lnet_nid *nid)
225 {
226         struct lu_nid_range *range = NULL;
227
228         if (nid_is_nid4(nid)) {
229                 struct nodemap_range_tree *nm_range_tree;
230
231                 nm_range_tree = &config->nmc_range_tree;
232                 range = nm_range_iter_first(&nm_range_tree->nmrt_range_interval_root,
233                                             lnet_nid_to_nid4(nid),
234                                             lnet_nid_to_nid4(nid));
235         } else if (!list_empty(&config->nmc_netmask_setup)) {
236                 struct lu_nid_range *range_temp;
237
238                 /* FIXME. We scan the config for the large NIDs. Each range
239                  * only contains one large NID for now.
240                  */
241                 list_for_each_entry_safe(range, range_temp,
242                                          &config->nmc_netmask_setup,
243                                          rn_collect) {
244                         if (nid_same(&range->rn_start, nid))
245                                 break;
246                         range = NULL;
247                 }
248         }
249
250         return range;
251 }