Whamcloud - gitweb
d261d651e6bca0bdc542920fc7a701546d37196e
[fs/lustre-release.git] / lustre / nodemap / nodemap_handler.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 #include <linux/module.h>
27 #include <lustre_net.h>
28 #include "nodemap_internal.h"
29
30 #define HASH_NODEMAP_BKT_BITS 3
31 #define HASH_NODEMAP_CUR_BITS 3
32 #define HASH_NODEMAP_MAX_BITS 7
33
34 #define DEFAULT_NODEMAP "default"
35
36 /* nodemap proc root proc directory under fs/lustre */
37 struct proc_dir_entry *proc_lustre_nodemap_root;
38
39 /* Highest numerical lu_nodemap.nm_id defined */
40 static atomic_t nodemap_highest_id;
41
42 /* Simple flag to determine if nodemaps are active */
43 bool nodemap_idmap_active;
44
45 /**
46  * pointer to default nodemap kept to keep from
47  * lookup it up in the hash since it is needed
48  * more often
49  */
50 static struct lu_nodemap *default_nodemap;
51
52 /**
53  * Hash keyed on nodemap name containing all
54  * nodemaps
55  */
56 static cfs_hash_t *nodemap_hash;
57
58 /**
59  * Nodemap destructor
60  *
61  * \param       nodemap         nodemap to destroy
62  */
63 static void nodemap_destroy(struct lu_nodemap *nodemap)
64 {
65         lprocfs_remove(&(nodemap->nm_proc_entry));
66         OBD_FREE_PTR(nodemap);
67 }
68
69 /**
70  * Functions used for the cfs_hash
71  */
72 static void nodemap_getref(struct lu_nodemap *nodemap)
73 {
74         CDEBUG(D_INFO, "nodemap %p\n", nodemap);
75         atomic_inc(&nodemap->nm_refcount);
76 }
77
78 void nodemap_putref(struct lu_nodemap *nodemap)
79 {
80         LASSERT(nodemap != NULL);
81         LASSERT(cfs_atomic_read(&nodemap->nm_refcount) > 0);
82
83         if (atomic_dec_and_test(&nodemap->nm_refcount))
84                 nodemap_destroy(nodemap);
85 }
86
87 static __u32 nodemap_hashfn(cfs_hash_t *hash_body,
88                             const void *key, unsigned mask)
89 {
90         const struct lu_nodemap *nodemap = key;
91
92         return cfs_hash_djb2_hash(nodemap->nm_name, strlen(nodemap->nm_name),
93                                   mask);
94 }
95
96 static void *nodemap_hs_key(cfs_hlist_node_t *hnode)
97 {
98         struct lu_nodemap *nodemap;
99
100         nodemap = cfs_hlist_entry(hnode, struct lu_nodemap, nm_hash);
101         return nodemap->nm_name;
102 }
103
104 static int nodemap_hs_keycmp(const void *key,
105                              cfs_hlist_node_t *compared_hnode)
106 {
107         struct lu_nodemap *nodemap;
108
109         nodemap = nodemap_hs_key(compared_hnode);
110         return !strcmp(key, nodemap->nm_name);
111 }
112
113 static void *nodemap_hs_hashobject(cfs_hlist_node_t *hnode)
114 {
115         return cfs_hlist_entry(hnode, struct lu_nodemap, nm_hash);
116 }
117
118 static void nodemap_hs_get(cfs_hash_t *hs, cfs_hlist_node_t *hnode)
119 {
120         struct lu_nodemap *nodemap;
121
122         nodemap = cfs_hlist_entry(hnode, struct lu_nodemap, nm_hash);
123         nodemap_getref(nodemap);
124 }
125
126 static void nodemap_hs_put_locked(cfs_hash_t *hs,
127                                   cfs_hlist_node_t *hnode)
128 {
129         struct lu_nodemap *nodemap;
130
131         nodemap = cfs_hlist_entry(hnode, struct lu_nodemap, nm_hash);
132         nodemap_putref(nodemap);
133 }
134
135 static cfs_hash_ops_t nodemap_hash_operations = {
136         .hs_hash        = nodemap_hashfn,
137         .hs_key         = nodemap_hs_key,
138         .hs_keycmp      = nodemap_hs_keycmp,
139         .hs_object      = nodemap_hs_hashobject,
140         .hs_get         = nodemap_hs_get,
141         .hs_put_locked  = nodemap_hs_put_locked,
142 };
143
144 /* end of cfs_hash functions */
145
146 /**
147  * Helper iterator to clean up nodemap on module exit.
148  *
149  * \param       hs              hash structure
150  * \param       bd              bucket descriptor
151  * \param       hnode           hash node
152  * \param       data            not used here
153  */
154 static int nodemap_cleanup_iter_cb(cfs_hash_t *hs, cfs_hash_bd_t *bd,
155                                    cfs_hlist_node_t *hnode, void *data)
156 {
157         struct lu_nodemap *nodemap;
158
159         nodemap = cfs_hlist_entry(hnode, struct lu_nodemap, nm_hash);
160         nodemap_putref(nodemap);
161
162         return 0;
163 }
164
165 /**
166  * Walk the nodemap_hash and remove all nodemaps.
167  */
168 void nodemap_cleanup_all(void)
169 {
170         cfs_hash_for_each_safe(nodemap_hash, nodemap_cleanup_iter_cb, NULL);
171         cfs_hash_putref(nodemap_hash);
172 }
173
174 /**
175  * Initialize nodemap_hash
176  *
177  * \retval      0               success
178  * \retval      -ENOMEM         cannot create hash
179  */
180 static int nodemap_init_hash(void)
181 {
182         nodemap_hash = cfs_hash_create("NODEMAP", HASH_NODEMAP_CUR_BITS,
183                                        HASH_NODEMAP_MAX_BITS,
184                                        HASH_NODEMAP_BKT_BITS, 0,
185                                        CFS_HASH_MIN_THETA,
186                                        CFS_HASH_MAX_THETA,
187                                        &nodemap_hash_operations,
188                                        CFS_HASH_DEFAULT);
189
190         if (nodemap_hash == NULL) {
191                 CERROR("cannot create nodemap_hash table\n");
192                 return -ENOMEM;
193         }
194
195         return 0;
196 }
197
198 /**
199  * Check for valid nodemap name
200  *
201  * \param       name            nodemap name
202  * \retval      true            valid
203  * \retval      false           invalid
204  */
205 static bool nodemap_name_is_valid(const char *name)
206 {
207         for (; *name != '\0'; name++) {
208                 if (!isalnum(*name) && *name != '_')
209                         return false;
210         }
211         return true;
212 }
213
214 /**
215  * Nodemap lookup
216  *
217  * Look nodemap up in the nodemap hash
218  *
219  * \param       name            name of nodemap
220  * \paramA      nodemap         found nodemap or NULL
221  * \retval      lu_nodemap      named nodemap
222  * \retval      NULL            nodemap doesn't exist
223  */
224 static int nodemap_lookup(const char *name, struct lu_nodemap **nodemap)
225 {
226         int rc = 0;
227
228         if (!nodemap_name_is_valid(name))
229                 GOTO(out, rc = -EINVAL);
230
231         *nodemap = cfs_hash_lookup(nodemap_hash, name);
232
233 out:
234         return rc;
235 }
236
237 /**
238  * Nodemap constructor
239  *
240  * Creates an lu_nodemap structure and assigns sane default
241  * member values. If this is the default nodemap, the defaults
242  * are the most restictive in xterms of mapping behavior. Otherwise
243  * the default flags should be inherited from the default nodemap.
244  * The adds nodemap to nodemap_hash.
245  *
246  * \param       name            name of nodemap
247  * \param       is_default      true if default nodemap
248  * \retval      0               success
249  * \retval      -EINVAL         invalid nodemap name
250  * \retval      -EEXIST         nodemap already exists
251  * \retval      -ENOMEM         cannot allocate memory for nodemap
252  */
253 static int nodemap_create(const char *name, bool is_default)
254 {
255         struct  lu_nodemap *nodemap = NULL;
256         int     rc = 0;
257
258         rc = nodemap_lookup(name, &nodemap);
259         if (rc < 0)
260                 goto out;
261
262         if (nodemap != NULL) {
263                 nodemap_putref(nodemap);
264                 GOTO(out, rc = -EEXIST);
265         }
266
267         OBD_ALLOC_PTR(nodemap);
268
269         if (nodemap == NULL) {
270                 CERROR("cannot allocate memory (%zu bytes)"
271                        "for nodemap '%s'\n", sizeof(*nodemap),
272                        name);
273                 GOTO(out, rc = -ENOMEM);
274         }
275
276         snprintf(nodemap->nm_name, sizeof(nodemap->nm_name), "%s", name);
277
278         INIT_LIST_HEAD(&(nodemap->nm_ranges));
279         nodemap->nm_local_to_remote_uidmap = RB_ROOT;
280         nodemap->nm_remote_to_local_uidmap = RB_ROOT;
281         nodemap->nm_local_to_remote_gidmap = RB_ROOT;
282         nodemap->nm_remote_to_local_gidmap = RB_ROOT;
283
284         if (is_default) {
285                 nodemap->nm_id = LUSTRE_NODEMAP_DEFAULT_ID;
286                 nodemap->nmf_trust_client_ids = 0;
287                 nodemap->nmf_allow_root_access = 0;
288                 nodemap->nmf_block_lookups = 0;
289
290                 nodemap->nm_squash_uid = NODEMAP_NOBODY_UID;
291                 nodemap->nm_squash_gid = NODEMAP_NOBODY_GID;
292
293                 lprocfs_nodemap_register(name, is_default, nodemap);
294
295                 default_nodemap = nodemap;
296         } else {
297                 nodemap->nm_id = atomic_inc_return(&nodemap_highest_id);
298                 nodemap->nmf_trust_client_ids =
299                                 default_nodemap->nmf_trust_client_ids;
300                 nodemap->nmf_allow_root_access =
301                                 default_nodemap->nmf_allow_root_access;
302                 nodemap->nmf_block_lookups =
303                                 default_nodemap->nmf_block_lookups;
304
305                 nodemap->nm_squash_uid = default_nodemap->nm_squash_uid;
306                 nodemap->nm_squash_gid = default_nodemap->nm_squash_gid;
307
308                 lprocfs_nodemap_register(name, is_default, nodemap);
309         }
310
311         atomic_set(&nodemap->nm_refcount, 1);
312         rc = cfs_hash_add_unique(nodemap_hash, name, &nodemap->nm_hash);
313
314         if (rc == 0)
315                 goto out;
316
317         CERROR("cannot add nodemap: '%s': rc = %d\n", name, rc);
318         nodemap_destroy(nodemap);
319
320 out:
321         return rc;
322 }
323
324 /**
325  * Add a nodemap
326  *
327  * \param       name            name of nodemap
328  * \retval      0               success
329  * \retval      -EINVAL         invalid nodemap name
330  * \retval      -EEXIST         nodemap already exists
331  * \retval      -ENOMEM         cannot allocate memory for nodemap
332  */
333 int nodemap_add(const char *name)
334 {
335         return nodemap_create(name, 0);
336 }
337 EXPORT_SYMBOL(nodemap_add);
338
339 /**
340  * Delete a nodemap
341  *
342  * \param       name            name of nodemmap
343  * \retval      0               success
344  * \retval      -EINVAL         invalid input
345  * \retval      -ENOENT         no existing nodemap
346  */
347 int nodemap_del(const char *name)
348 {
349         struct  lu_nodemap *nodemap;
350         int     rc = 0;
351
352         if (strcmp(name, DEFAULT_NODEMAP) == 0)
353                 GOTO(out, rc = -EINVAL);
354
355         nodemap = cfs_hash_del_key(nodemap_hash, name);
356         if (nodemap == NULL)
357                 GOTO(out, rc = -ENOENT);
358
359         nodemap_putref(nodemap);
360 out:
361         return rc;
362 }
363 EXPORT_SYMBOL(nodemap_del);
364
365 /**
366  * Cleanup nodemap module on exit
367  */
368 static void nodemap_mod_exit(void)
369 {
370         nodemap_cleanup_all();
371         lprocfs_remove(&proc_lustre_nodemap_root);
372 }
373
374 /**
375  * Initialize the nodemap module
376  */
377 static int __init nodemap_mod_init(void)
378 {
379         int rc = 0;
380
381         rc = nodemap_init_hash();
382         if (rc != 0)
383                 goto cleanup;
384
385         nodemap_procfs_init();
386         rc = nodemap_create(DEFAULT_NODEMAP, 1);
387
388 cleanup:
389         if (rc != 0)
390                 nodemap_mod_exit();
391
392         return rc;
393 }
394
395 MODULE_LICENSE("GPL");
396 MODULE_DESCRIPTION("Lustre Client Nodemap Management Module");
397 MODULE_AUTHOR("Joshua Walgenbach <jjw@iu.edu>");
398
399 module_init(nodemap_mod_init);
400 module_exit(nodemap_mod_exit);