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>
27 #include <lustre_net.h>
28 #include "nodemap_internal.h"
29 #include <linux/interval_tree_generic.h>
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.
43 #define START(node) (lnet_nid_to_nid4(&((node)->rn_start)))
44 #define LAST(node) (lnet_nid_to_nid4(&((node)->rn_end)))
46 INTERVAL_TREE_DEFINE(struct lu_nid_range, rn_rb, lnet_nid_t, rn_subtree_last,
47 START, LAST, static, nm_range)
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
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)
63 struct nodemap_range_tree *nm_range_tree;
64 struct lu_nid_range *range;
66 if (LNET_NID_NET(start_nid) != LNET_NID_NET(end_nid))
70 lnet_nid_t nid4[2] = {
71 lnet_nid_to_nid4(start_nid),
72 lnet_nid_to_nid4(end_nid)
75 if (LNET_NIDADDR(nid4[0]) > LNET_NIDADDR(nid4[1]))
77 } else if (!nid_same(start_nid, end_nid)) {
78 /* FIXME Currently we only support one large NID per nodemap */
84 CERROR("cannot allocate lu_nid_range of size %zu bytes\n",
89 /* if we are loading from save, use on disk id num */
90 nm_range_tree = &config->nmc_range_tree;
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;
96 nm_range_tree->nmrt_range_highest_id++;
97 range->rn_id = nm_range_tree->nmrt_range_highest_id;
99 range->rn_nodemap = nodemap;
101 range->rn_netmask = netmask;
102 range->rn_start = *start_nid;
103 range->rn_end = *end_nid;
105 INIT_LIST_HEAD(&range->rn_list);
111 * find the exact range
113 * \param start_nid starting nid
114 * \param end_nid ending nid
115 * \retval matching range or NULL
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,
122 struct lu_nid_range *range = NULL;
125 struct nodemap_range_tree *nm_range_tree;
128 if (!nid_is_nid4(start_nid) || !nid_is_nid4(end_nid))
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,
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;
143 /* FIXME. We scan the config for large NIDs. Each range
144 * only contains one large NID for now.
146 list_for_each_entry_safe(range, range_temp,
147 &config->nmc_netmask_setup,
149 if (nid_same(&range->rn_start, start_nid) &&
150 range->rn_netmask == netmask)
161 void range_destroy(struct lu_nid_range *range)
163 LASSERT(list_empty(&range->rn_list) == 0);
169 * insert an nid range into the interval tree
171 * \param range range to insetr
172 * \retval 0 on success
174 * This function checks that the given nid range
175 * does not overlap so that each nid can belong
176 * to exactly one range
178 int range_insert(struct nodemap_config *config, struct lu_nid_range *range)
180 if (!range->rn_netmask) {
181 struct nodemap_range_tree *nm_range_tree;
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)))
189 nm_range_insert(range,
190 &nm_range_tree->nmrt_range_interval_root);
192 list_add(&range->rn_collect, &config->nmc_netmask_setup);
198 * delete a range from the interval tree and any
199 * associated nodemap references
201 * \param range range to remove
203 void range_delete(struct nodemap_config *config, struct lu_nid_range *range)
205 list_del(&range->rn_list);
206 if (!range->rn_netmask) {
207 struct nodemap_range_tree *nm_range_tree;
209 nm_range_tree = &config->nmc_range_tree;
210 nm_range_remove(range,
211 &nm_range_tree->nmrt_range_interval_root);
213 list_del(&range->rn_collect);
215 range_destroy(range);
219 * search the interval tree for an nid within a range
221 * \param nid nid to search for
223 struct lu_nid_range *range_search(struct nodemap_config *config,
224 struct lnet_nid *nid)
226 struct lu_nid_range *range = NULL;
228 if (nid_is_nid4(nid)) {
229 struct nodemap_range_tree *nm_range_tree;
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;
238 /* FIXME. We scan the config for the large NIDs. Each range
239 * only contains one large NID for now.
241 list_for_each_entry_safe(range, range_temp,
242 &config->nmc_netmask_setup,
244 if (nid_same(&range->rn_start, nid))