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;
106 fwd_root = &nodemap->nm_client_to_fs_gidmap;
107 bck_root = &nodemap->nm_fs_to_client_gidmap;
110 fwd_node = &fwd_root->rb_node;
111 bck_node = &bck_root->rb_node;
113 /* find fwd and bck idmap nodes before insertion or
114 * replacing to prevent split brain idmaps
117 fwd_parent = *fwd_node;
118 fwd_cur = rb_entry(*fwd_node, struct lu_idmap,
121 if (idmap->id_client < fwd_cur->id_client) {
122 fwd_node = &((*fwd_node)->rb_left);
123 } else if (idmap->id_client > fwd_cur->id_client) {
124 fwd_node = &((*fwd_node)->rb_right);
132 bck_parent = *bck_node;
133 bck_cur = rb_entry(*bck_node, struct lu_idmap,
136 if (idmap->id_fs < bck_cur->id_fs) {
137 bck_node = &((*bck_node)->rb_left);
138 } else if (idmap->id_fs > bck_cur->id_fs) {
139 bck_node = &((*bck_node)->rb_right);
147 if (fwd_found && bck_found)
148 RETURN(ERR_PTR(-EEXIST));
150 /* Insert a new idmap */
151 if (!fwd_found && !bck_found) {
152 CDEBUG(D_INFO, "Insert a new idmap %d:%d\n",
153 idmap->id_client, idmap->id_fs);
154 rb_link_node(&idmap->id_client_to_fs, fwd_parent, fwd_node);
155 rb_insert_color(&idmap->id_client_to_fs, fwd_root);
156 rb_link_node(&idmap->id_fs_to_client, bck_parent, bck_node);
157 rb_insert_color(&idmap->id_fs_to_client, bck_root);
161 /* Only id_client or id_fs is matched */
162 RETURN(fwd_found ? fwd_cur : bck_cur);
166 * Delete idmap from the correct nodemap tree
168 * \param node_type 0 for UID
170 * \param idmap idmap to delete
171 * \param nodemap assoicated idmap
173 void idmap_delete(enum nodemap_id_type id_type, struct lu_idmap *idmap,
174 struct lu_nodemap *nodemap)
176 struct rb_root *fwd_root;
177 struct rb_root *bck_root;
179 if (id_type == NODEMAP_UID) {
180 fwd_root = &nodemap->nm_client_to_fs_uidmap;
181 bck_root = &nodemap->nm_fs_to_client_uidmap;
183 fwd_root = &nodemap->nm_client_to_fs_gidmap;
184 bck_root = &nodemap->nm_fs_to_client_gidmap;
187 rb_erase(&idmap->id_client_to_fs, fwd_root);
188 rb_erase(&idmap->id_fs_to_client, bck_root);
190 idmap_destroy(idmap);
194 * Search for an existing id in the nodemap trees.
196 * \param nodemap nodemap trees to search
197 * \param tree_type 0 for filesystem to client maps
198 * 1 for client to filesystem maps
199 * \param id_type 0 for UID
201 * \param id numeric id for which to search
203 * \retval lu_idmap structure with the map on success
205 struct lu_idmap *idmap_search(struct lu_nodemap *nodemap,
206 enum nodemap_tree_type tree_type,
207 enum nodemap_id_type id_type,
210 struct rb_node *node;
211 struct rb_root *root = NULL;
212 struct lu_idmap *idmap;
216 if (id_type == NODEMAP_UID && tree_type == NODEMAP_FS_TO_CLIENT)
217 root = &nodemap->nm_fs_to_client_uidmap;
218 else if (id_type == NODEMAP_UID && tree_type == NODEMAP_CLIENT_TO_FS)
219 root = &nodemap->nm_client_to_fs_uidmap;
220 else if (id_type == NODEMAP_GID && tree_type == NODEMAP_FS_TO_CLIENT)
221 root = &nodemap->nm_fs_to_client_gidmap;
222 else if (id_type == NODEMAP_GID && tree_type == NODEMAP_CLIENT_TO_FS)
223 root = &nodemap->nm_client_to_fs_gidmap;
225 node = root->rb_node;
227 if (tree_type == NODEMAP_FS_TO_CLIENT) {
229 idmap = rb_entry(node, struct lu_idmap,
231 if (id < idmap->id_fs)
232 node = node->rb_left;
233 else if (id > idmap->id_fs)
234 node = node->rb_right;
240 idmap = rb_entry(node, struct lu_idmap,
242 if (id < idmap->id_client)
243 node = node->rb_left;
244 else if (id > idmap->id_client)
245 node = node->rb_right;
255 * delete all idmap trees from a nodemap
257 * \param nodemap nodemap to delete trees from
259 * This uses the postorder safe traversal code that is committed
260 * in a later kernel. Each lu_idmap strucuture is destroyed.
262 void idmap_delete_tree(struct lu_nodemap *nodemap)
264 struct lu_idmap *idmap;
265 struct lu_idmap *temp;
268 root = nodemap->nm_fs_to_client_uidmap;
269 nm_rbtree_postorder_for_each_entry_safe(idmap, temp, &root,
271 idmap_destroy(idmap);
274 root = nodemap->nm_client_to_fs_gidmap;
275 nm_rbtree_postorder_for_each_entry_safe(idmap, temp, &root,
277 idmap_destroy(idmap);