Whamcloud - gitweb
LU-17744 ldiskfs: mballoc stats fixes
[fs/lustre-release.git] / lustre / ptlrpc / nodemap_idmap.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  *
25  * Copyright (c) 2017, Intel Corporation.
26  *
27  * Author: Joshua Walgenbach <jjw@iu.edu>
28  */
29
30 #include <linux/rbtree.h>
31 #include <lustre_net.h>
32 #include "nodemap_internal.h"
33
34 /**
35  * Allocate the lu_idmap structure
36  *
37  * \param       client_id               client uid or gid
38  * \param       fs_id                   filesystem uid or gid
39  *
40  * \retval      alloated lu_idmap structure on success, NULL otherwise
41  */
42 struct lu_idmap *idmap_create(__u32 client_id, __u32 fs_id)
43 {
44         struct lu_idmap *idmap;
45
46         OBD_ALLOC_PTR(idmap);
47         if (idmap == NULL) {
48                 CERROR("cannot allocate lu_idmap of size %zu bytes\n",
49                        sizeof(idmap));
50                 return NULL;
51         }
52
53         idmap->id_client = client_id;
54         idmap->id_fs = fs_id;
55         RB_CLEAR_NODE(&idmap->id_client_to_fs);
56         RB_CLEAR_NODE(&idmap->id_fs_to_client);
57         return idmap;
58 }
59
60 static void idmap_destroy(struct lu_idmap *idmap)
61
62 {
63         LASSERT(RB_EMPTY_NODE(&idmap->id_fs_to_client) == 0);
64         LASSERT(RB_EMPTY_NODE(&idmap->id_client_to_fs) == 0);
65         OBD_FREE_PTR(idmap);
66 }
67
68 /**
69  * Insert idmap into the proper trees
70  *
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
74  *
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.
81  */
82 struct lu_idmap *idmap_insert(enum nodemap_id_type id_type,
83                               struct lu_idmap *idmap,
84                               struct lu_nodemap *nodemap)
85 {
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;
96
97         ENTRY;
98
99         /* for purposes in idmap client to fs is forward
100          * mapping, fs to client is backward mapping
101          */
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;
111         } else {
112                 RETURN(ERR_PTR(-EINVAL));
113         }
114
115         fwd_node = &fwd_root->rb_node;
116         bck_node = &bck_root->rb_node;
117
118         /* find fwd and bck idmap nodes before insertion or
119          * replacing to prevent split brain idmaps
120          */
121         while (*fwd_node) {
122                 fwd_parent = *fwd_node;
123                 fwd_cur = rb_entry(*fwd_node, struct lu_idmap,
124                                    id_client_to_fs);
125
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);
130                 } else {
131                         fwd_found = true;
132                         break;
133                 }
134         }
135
136         while (*bck_node) {
137                 bck_parent = *bck_node;
138                 bck_cur = rb_entry(*bck_node, struct lu_idmap,
139                                    id_fs_to_client);
140
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);
145                 } else {
146                         bck_found = true;
147                         break;
148                 }
149         }
150
151         /* Already exists */
152         if (fwd_found && bck_found)
153                 RETURN(ERR_PTR(-EEXIST));
154
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);
163                 RETURN(NULL);
164         }
165
166         /* Only id_client or id_fs is matched */
167         RETURN(fwd_found ? fwd_cur : bck_cur);
168 }
169
170 /**
171  * Delete idmap from the correct nodemap tree
172  *
173  * \param       node_type               0 for UID
174  *                                      1 for GID
175  * \param       idmap                   idmap to delete
176  * \param       nodemap                 assoicated idmap
177  */
178 void idmap_delete(enum nodemap_id_type id_type, struct lu_idmap *idmap,
179                   struct lu_nodemap *nodemap)
180 {
181         struct rb_root *fwd_root;
182         struct rb_root *bck_root;
183
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;
193         } else {
194                 return;
195         }
196
197         rb_erase(&idmap->id_client_to_fs, fwd_root);
198         rb_erase(&idmap->id_fs_to_client, bck_root);
199
200         idmap_destroy(idmap);
201 }
202
203 /**
204  * Search for an existing id in the nodemap trees.
205  *
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
210  *                              1 for GID
211  * \param       id              numeric id for which to search
212  *
213  * \retval      lu_idmap structure with the map on success
214  */
215 struct lu_idmap *idmap_search(struct lu_nodemap *nodemap,
216                               enum nodemap_tree_type tree_type,
217                               enum nodemap_id_type id_type,
218                               const __u32 id)
219 {
220         struct rb_node  *node;
221         struct rb_root  *root = NULL;
222         struct lu_idmap *idmap;
223
224         ENTRY;
225
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;
238
239         node = root->rb_node;
240
241         if (tree_type == NODEMAP_FS_TO_CLIENT) {
242                 while (node) {
243                         idmap = rb_entry(node, struct lu_idmap,
244                                          id_fs_to_client);
245                         if (id < idmap->id_fs)
246                                 node = node->rb_left;
247                         else if (id > idmap->id_fs)
248                                 node = node->rb_right;
249                         else
250                                 RETURN(idmap);
251                 }
252         } else {
253                 while (node) {
254                         idmap = rb_entry(node, struct lu_idmap,
255                                          id_client_to_fs);
256                         if (id < idmap->id_client)
257                                 node = node->rb_left;
258                         else if (id > idmap->id_client)
259                                 node = node->rb_right;
260                         else
261                                 RETURN(idmap);
262                 }
263         }
264
265         RETURN(NULL);
266 }
267
268 /*
269  * delete all idmap trees from a nodemap
270  *
271  * \param       nodemap         nodemap to delete trees from
272  *
273  * This uses the postorder safe traversal code that is committed
274  * in a later kernel. Each lu_idmap strucuture is destroyed.
275  */
276 void idmap_delete_tree(struct lu_nodemap *nodemap)
277 {
278         struct lu_idmap         *idmap;
279         struct lu_idmap         *temp;
280         struct rb_root          root;
281
282         root = nodemap->nm_fs_to_client_uidmap;
283         rbtree_postorder_for_each_entry_safe(idmap, temp, &root,
284                                              id_fs_to_client) {
285                 idmap_destroy(idmap);
286         }
287
288         root = nodemap->nm_client_to_fs_gidmap;
289         rbtree_postorder_for_each_entry_safe(idmap, temp, &root,
290                                              id_client_to_fs) {
291                 idmap_destroy(idmap);
292         }
293
294         root = nodemap->nm_client_to_fs_projidmap;
295         rbtree_postorder_for_each_entry_safe(idmap, temp, &root,
296                                              id_client_to_fs) {
297                 idmap_destroy(idmap);
298         }
299 }