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
25 * Copyright (c) 2017, Intel Corporation.
27 * Author: Joshua Walgenbach <jjw@iu.edu>
30 #include <linux/rbtree.h>
31 #include <lustre_net.h>
32 #include "nodemap_internal.h"
35 * Allocate the lu_idmap structure
37 * \param client_id client uid or gid
38 * \param fs_id filesystem uid or gid
40 * \retval alloated lu_idmap structure on success, NULL otherwise
42 struct lu_idmap *idmap_create(__u32 client_id, __u32 fs_id)
44 struct lu_idmap *idmap;
48 CERROR("cannot allocate lu_idmap of size %zu bytes\n",
53 idmap->id_client = client_id;
55 RB_CLEAR_NODE(&idmap->id_client_to_fs);
56 RB_CLEAR_NODE(&idmap->id_fs_to_client);
60 static void idmap_destroy(struct lu_idmap *idmap)
63 LASSERT(RB_EMPTY_NODE(&idmap->id_fs_to_client) == 0);
64 LASSERT(RB_EMPTY_NODE(&idmap->id_client_to_fs) == 0);
69 * Insert idmap into the proper trees
71 * \param id_type NODEMAP_UID or NODEMAP_GID
72 * \param idmap lu_idmap structure to insert
73 * \param nodemap nodemap to associate with the map
75 * \retval NULL on success
76 * \retval ERR_PTR(-EEXIST) if this idmap already exists
77 * \retval struct lu_idmap if only id_client or id_fs of this idmap
78 * is matched, return the matched idmap.
79 * The caller will delete this old idmap and
80 * its index before insert the new idmap again.
82 struct lu_idmap *idmap_insert(enum nodemap_id_type id_type,
83 struct lu_idmap *idmap,
84 struct lu_nodemap *nodemap)
86 struct lu_idmap *fwd_cur = NULL;
87 struct lu_idmap *bck_cur = NULL;
88 struct rb_node *fwd_parent = NULL;
89 struct rb_node *bck_parent = NULL;
90 struct rb_node **fwd_node;
91 struct rb_node **bck_node;
92 struct rb_root *fwd_root;
93 struct rb_root *bck_root;
94 bool fwd_found = false;
95 bool bck_found = false;
99 /* for purposes in idmap client to fs is forward
100 * mapping, fs to client is backward mapping
102 if (id_type == NODEMAP_UID) {
103 fwd_root = &nodemap->nm_client_to_fs_uidmap;
104 bck_root = &nodemap->nm_fs_to_client_uidmap;
105 } else if (id_type == NODEMAP_GID) {
106 fwd_root = &nodemap->nm_client_to_fs_gidmap;
107 bck_root = &nodemap->nm_fs_to_client_gidmap;
108 } else if (id_type == NODEMAP_PROJID) {
109 fwd_root = &nodemap->nm_client_to_fs_projidmap;
110 bck_root = &nodemap->nm_fs_to_client_projidmap;
112 RETURN(ERR_PTR(-EINVAL));
115 fwd_node = &fwd_root->rb_node;
116 bck_node = &bck_root->rb_node;
118 /* find fwd and bck idmap nodes before insertion or
119 * replacing to prevent split brain idmaps
122 fwd_parent = *fwd_node;
123 fwd_cur = rb_entry(*fwd_node, struct lu_idmap,
126 if (idmap->id_client < fwd_cur->id_client) {
127 fwd_node = &((*fwd_node)->rb_left);
128 } else if (idmap->id_client > fwd_cur->id_client) {
129 fwd_node = &((*fwd_node)->rb_right);
137 bck_parent = *bck_node;
138 bck_cur = rb_entry(*bck_node, struct lu_idmap,
141 if (idmap->id_fs < bck_cur->id_fs) {
142 bck_node = &((*bck_node)->rb_left);
143 } else if (idmap->id_fs > bck_cur->id_fs) {
144 bck_node = &((*bck_node)->rb_right);
152 if (fwd_found && bck_found)
153 RETURN(ERR_PTR(-EEXIST));
155 /* Insert a new idmap */
156 if (!fwd_found && !bck_found) {
157 CDEBUG(D_INFO, "Insert a new idmap %d:%d\n",
158 idmap->id_client, idmap->id_fs);
159 rb_link_node(&idmap->id_client_to_fs, fwd_parent, fwd_node);
160 rb_insert_color(&idmap->id_client_to_fs, fwd_root);
161 rb_link_node(&idmap->id_fs_to_client, bck_parent, bck_node);
162 rb_insert_color(&idmap->id_fs_to_client, bck_root);
166 /* Only id_client or id_fs is matched */
167 RETURN(fwd_found ? fwd_cur : bck_cur);
171 * Delete idmap from the correct nodemap tree
173 * \param node_type 0 for UID
175 * \param idmap idmap to delete
176 * \param nodemap assoicated idmap
178 void idmap_delete(enum nodemap_id_type id_type, struct lu_idmap *idmap,
179 struct lu_nodemap *nodemap)
181 struct rb_root *fwd_root;
182 struct rb_root *bck_root;
184 if (id_type == NODEMAP_UID) {
185 fwd_root = &nodemap->nm_client_to_fs_uidmap;
186 bck_root = &nodemap->nm_fs_to_client_uidmap;
187 } else if (id_type == NODEMAP_GID) {
188 fwd_root = &nodemap->nm_client_to_fs_gidmap;
189 bck_root = &nodemap->nm_fs_to_client_gidmap;
190 } else if (id_type == NODEMAP_PROJID) {
191 fwd_root = &nodemap->nm_client_to_fs_projidmap;
192 bck_root = &nodemap->nm_fs_to_client_projidmap;
197 rb_erase(&idmap->id_client_to_fs, fwd_root);
198 rb_erase(&idmap->id_fs_to_client, bck_root);
200 idmap_destroy(idmap);
204 * Search for an existing id in the nodemap trees.
206 * \param nodemap nodemap trees to search
207 * \param tree_type 0 for filesystem to client maps
208 * 1 for client to filesystem maps
209 * \param id_type 0 for UID
211 * \param id numeric id for which to search
213 * \retval lu_idmap structure with the map on success
215 struct lu_idmap *idmap_search(struct lu_nodemap *nodemap,
216 enum nodemap_tree_type tree_type,
217 enum nodemap_id_type id_type,
220 struct rb_node *node;
221 struct rb_root *root = NULL;
222 struct lu_idmap *idmap;
226 if (id_type == NODEMAP_UID && tree_type == NODEMAP_FS_TO_CLIENT)
227 root = &nodemap->nm_fs_to_client_uidmap;
228 else if (id_type == NODEMAP_UID && tree_type == NODEMAP_CLIENT_TO_FS)
229 root = &nodemap->nm_client_to_fs_uidmap;
230 else if (id_type == NODEMAP_GID && tree_type == NODEMAP_FS_TO_CLIENT)
231 root = &nodemap->nm_fs_to_client_gidmap;
232 else if (id_type == NODEMAP_GID && tree_type == NODEMAP_CLIENT_TO_FS)
233 root = &nodemap->nm_client_to_fs_gidmap;
234 else if (id_type == NODEMAP_PROJID && tree_type == NODEMAP_FS_TO_CLIENT)
235 root = &nodemap->nm_fs_to_client_projidmap;
236 else if (id_type == NODEMAP_PROJID && tree_type == NODEMAP_CLIENT_TO_FS)
237 root = &nodemap->nm_client_to_fs_projidmap;
239 node = root->rb_node;
241 if (tree_type == NODEMAP_FS_TO_CLIENT) {
243 idmap = rb_entry(node, struct lu_idmap,
245 if (id < idmap->id_fs)
246 node = node->rb_left;
247 else if (id > idmap->id_fs)
248 node = node->rb_right;
254 idmap = rb_entry(node, struct lu_idmap,
256 if (id < idmap->id_client)
257 node = node->rb_left;
258 else if (id > idmap->id_client)
259 node = node->rb_right;
269 * delete all idmap trees from a nodemap
271 * \param nodemap nodemap to delete trees from
273 * This uses the postorder safe traversal code that is committed
274 * in a later kernel. Each lu_idmap strucuture is destroyed.
276 void idmap_delete_tree(struct lu_nodemap *nodemap)
278 struct lu_idmap *idmap;
279 struct lu_idmap *temp;
282 root = nodemap->nm_fs_to_client_uidmap;
283 nm_rbtree_postorder_for_each_entry_safe(idmap, temp, &root,
285 idmap_destroy(idmap);
288 root = nodemap->nm_client_to_fs_gidmap;
289 nm_rbtree_postorder_for_each_entry_safe(idmap, temp, &root,
291 idmap_destroy(idmap);
294 root = nodemap->nm_client_to_fs_projidmap;
295 nm_rbtree_postorder_for_each_entry_safe(idmap, temp, &root,
297 idmap_destroy(idmap);