Whamcloud - gitweb
LU-3527 nodemap: add NID range management
[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         struct lu_nid_range *range;
66         struct lu_nid_range *temp;
67
68         list_for_each_entry_safe(range, temp, &nodemap->nm_ranges,
69                                  rn_list) {
70                 range_delete(range);
71         }
72
73         lprocfs_remove(&nodemap->nm_proc_entry);
74         OBD_FREE_PTR(nodemap);
75 }
76
77 /**
78  * Functions used for the cfs_hash
79  */
80 static void nodemap_getref(struct lu_nodemap *nodemap)
81 {
82         CDEBUG(D_INFO, "nodemap %p\n", nodemap);
83         atomic_inc(&nodemap->nm_refcount);
84 }
85
86 void nodemap_putref(struct lu_nodemap *nodemap)
87 {
88         LASSERT(nodemap != NULL);
89         LASSERT(cfs_atomic_read(&nodemap->nm_refcount) > 0);
90
91         if (atomic_dec_and_test(&nodemap->nm_refcount))
92                 nodemap_destroy(nodemap);
93 }
94
95 static __u32 nodemap_hashfn(cfs_hash_t *hash_body,
96                             const void *key, unsigned mask)
97 {
98         const struct lu_nodemap *nodemap = key;
99
100         return cfs_hash_djb2_hash(nodemap->nm_name, strlen(nodemap->nm_name),
101                                   mask);
102 }
103
104 static void *nodemap_hs_key(cfs_hlist_node_t *hnode)
105 {
106         struct lu_nodemap *nodemap;
107
108         nodemap = cfs_hlist_entry(hnode, struct lu_nodemap, nm_hash);
109
110         return nodemap->nm_name;
111 }
112
113 static int nodemap_hs_keycmp(const void *key,
114                              cfs_hlist_node_t *compared_hnode)
115 {
116         struct lu_nodemap *nodemap;
117
118         nodemap = nodemap_hs_key(compared_hnode);
119
120         return !strcmp(key, nodemap->nm_name);
121 }
122
123 static void *nodemap_hs_hashobject(cfs_hlist_node_t *hnode)
124 {
125         return cfs_hlist_entry(hnode, struct lu_nodemap, nm_hash);
126 }
127
128 static void nodemap_hs_get(cfs_hash_t *hs, cfs_hlist_node_t *hnode)
129 {
130         struct lu_nodemap *nodemap;
131
132         nodemap = cfs_hlist_entry(hnode, struct lu_nodemap, nm_hash);
133         nodemap_getref(nodemap);
134 }
135
136 static void nodemap_hs_put_locked(cfs_hash_t *hs,
137                                   cfs_hlist_node_t *hnode)
138 {
139         struct lu_nodemap *nodemap;
140
141         nodemap = cfs_hlist_entry(hnode, struct lu_nodemap, nm_hash);
142         nodemap_putref(nodemap);
143 }
144
145 static cfs_hash_ops_t nodemap_hash_operations = {
146         .hs_hash        = nodemap_hashfn,
147         .hs_key         = nodemap_hs_key,
148         .hs_keycmp      = nodemap_hs_keycmp,
149         .hs_object      = nodemap_hs_hashobject,
150         .hs_get         = nodemap_hs_get,
151         .hs_put_locked  = nodemap_hs_put_locked,
152 };
153
154 /* end of cfs_hash functions */
155
156 /**
157  * Helper iterator to clean up nodemap on module exit.
158  *
159  * \param       hs              hash structure
160  * \param       bd              bucket descriptor
161  * \param       hnode           hash node
162  * \param       data            not used here
163  */
164 static int nodemap_cleanup_iter_cb(cfs_hash_t *hs, cfs_hash_bd_t *bd,
165                                    cfs_hlist_node_t *hnode, void *data)
166 {
167         struct lu_nodemap *nodemap;
168
169         nodemap = cfs_hlist_entry(hnode, struct lu_nodemap, nm_hash);
170         nodemap_putref(nodemap);
171
172         return 0;
173 }
174
175 /**
176  * Walk the nodemap_hash and remove all nodemaps.
177  */
178 void nodemap_cleanup_all(void)
179 {
180         cfs_hash_for_each_safe(nodemap_hash, nodemap_cleanup_iter_cb, NULL);
181         cfs_hash_putref(nodemap_hash);
182 }
183
184 /**
185  * Initialize nodemap_hash
186  *
187  * \retval      0               success
188  * \retval      -ENOMEM         cannot create hash
189  */
190 static int nodemap_init_hash(void)
191 {
192         nodemap_hash = cfs_hash_create("NODEMAP", HASH_NODEMAP_CUR_BITS,
193                                        HASH_NODEMAP_MAX_BITS,
194                                        HASH_NODEMAP_BKT_BITS, 0,
195                                        CFS_HASH_MIN_THETA,
196                                        CFS_HASH_MAX_THETA,
197                                        &nodemap_hash_operations,
198                                        CFS_HASH_DEFAULT);
199
200         if (nodemap_hash == NULL) {
201                 CERROR("cannot create nodemap_hash table\n");
202                 return -ENOMEM;
203         }
204
205         return 0;
206 }
207
208 /**
209  * Check for valid nodemap name
210  *
211  * \param       name            nodemap name
212  * \retval      true            valid
213  * \retval      false           invalid
214  */
215 static bool nodemap_name_is_valid(const char *name)
216 {
217         if (strlen(name) > LUSTRE_NODEMAP_NAME_LENGTH ||
218             strlen(name) == 0)
219                 return false;
220
221         for (; *name != '\0'; name++) {
222                 if (!isalnum(*name) && *name != '_')
223                         return false;
224         }
225         return true;
226 }
227
228 /**
229  * Nodemap lookup
230  *
231  * Look nodemap up in the nodemap hash
232  *
233  * \param       name            name of nodemap
234  * \param       nodemap         found nodemap or NULL
235  * \retval      lu_nodemap      named nodemap
236  * \retval      NULL            nodemap doesn't exist
237  */
238 static int nodemap_lookup(const char *name, struct lu_nodemap **nodemap)
239 {
240         int rc = 0;
241
242         *nodemap = NULL;
243
244         if (!nodemap_name_is_valid(name))
245                 GOTO(out, rc = -EINVAL);
246
247         *nodemap = cfs_hash_lookup(nodemap_hash, name);
248         if (*nodemap == NULL)
249                 rc = -ENOENT;
250
251 out:
252         return rc;
253 }
254
255 /**
256  * classify the nid into the proper nodemap
257  *
258  * \param       nid                     nid to classify
259  * \retval      nodemap                 nodemap containing the nid
260  * \retval      default_nodemap         default nodemap
261  */
262 struct lu_nodemap *nodemap_classify_nid(lnet_nid_t nid)
263 {
264         struct lu_nid_range     *range;
265
266         range = range_search(nid);
267         if (range != NULL)
268                 return range->rn_nodemap;
269
270         return default_nodemap;
271 }
272 EXPORT_SYMBOL(nodemap_classify_nid);
273
274 /*
275  * simple check for default nodemap
276  */
277 static bool is_default_nodemap(const struct lu_nodemap *nodemap)
278 {
279         return nodemap->nm_id == 0;
280 }
281
282 /*
283  * parse a nodemap range string into two nids
284  *
285  * \param       range_str               string to parse
286  * \param       range[2]                array of two nids
287  * \reyval      0 on success
288  */
289 int nodemap_parse_range(const char *range_str, lnet_nid_t range[2])
290 {
291         char    buf[LNET_NIDSTR_SIZE * 2 + 2];
292         char    *ptr = NULL;
293         char    *start_nidstr;
294         char    *end_nidstr;
295         int     rc = 0;
296
297         snprintf(buf, sizeof(buf), "%s", range_str);
298         ptr = buf;
299         start_nidstr = strsep(&ptr, ":");
300         end_nidstr = strsep(&ptr, ":");
301
302         if (start_nidstr == NULL || end_nidstr == NULL)
303                 GOTO(out, rc = -EINVAL);
304
305         range[0] = libcfs_str2nid(start_nidstr);
306         range[1] = libcfs_str2nid(end_nidstr);
307
308 out:
309         return rc;
310
311 }
312 EXPORT_SYMBOL(nodemap_parse_range);
313
314 /*
315  * add nid range to nodemap
316  * \param       name            nodemap name
317  * \param       range_st        string containing nid range
318  * \retval      0 on success
319  *
320  * add an range to the global range tree and attached the
321  * range to the named nodemap.
322  */
323 int nodemap_add_range(const char *name, const lnet_nid_t nid[2])
324 {
325         struct lu_nodemap       *nodemap = NULL;
326         struct lu_nid_range     *range;
327         int rc;
328
329         rc = nodemap_lookup(name, &nodemap);
330         if (nodemap == NULL || is_default_nodemap(nodemap))
331                 GOTO(out, rc = -EINVAL);
332
333         range = range_create(nid[0], nid[1], nodemap);
334         if (range == NULL)
335                 GOTO(out_putref, rc = -ENOMEM);
336
337         rc = range_insert(range);
338         if (rc != 0) {
339                 CERROR("cannot insert nodemap range into '%s': rc = %d\n",
340                       nodemap->nm_name, rc);
341                 list_del(&range->rn_list);
342                 range_destroy(range);
343                 GOTO(out_putref, rc = -ENOMEM);
344         }
345
346         list_add(&range->rn_list, &nodemap->nm_ranges);
347
348 out_putref:
349         nodemap_putref(nodemap);
350 out:
351         return rc;
352 }
353 EXPORT_SYMBOL(nodemap_add_range);
354
355 /**
356  * delete a range
357  * \param       name            nodemap name
358  * \param       range_str       string containing range
359  * \retval      0 on success
360  *
361  * Delete range from global range tree, and remove it
362  * from the list in the associated nodemap.
363  */
364 int nodemap_del_range(const char *name, const lnet_nid_t nid[2])
365 {
366         struct lu_nodemap       *nodemap;
367         struct lu_nid_range     *range;
368         int                     rc = 0;
369
370         rc = nodemap_lookup(name, &nodemap);
371         if (nodemap == NULL || is_default_nodemap(nodemap))
372                 GOTO(out, rc = -EINVAL);
373
374         range = range_find(nid[0], nid[1]);
375         if (range == NULL)
376                 GOTO(out_putref, rc = -EINVAL);
377
378         range_delete(range);
379
380 out_putref:
381         nodemap_putref(nodemap);
382 out:
383         return rc;
384 }
385 EXPORT_SYMBOL(nodemap_del_range);
386
387 /**
388  * Nodemap constructor
389  *
390  * Creates an lu_nodemap structure and assigns sane default
391  * member values. If this is the default nodemap, the defaults
392  * are the most restictive in xterms of mapping behavior. Otherwise
393  * the default flags should be inherited from the default nodemap.
394  * The adds nodemap to nodemap_hash.
395  *
396  * \param       name            name of nodemap
397  * \param       is_default      true if default nodemap
398  * \retval      0               success
399  * \retval      -EINVAL         invalid nodemap name
400  * \retval      -EEXIST         nodemap already exists
401  * \retval      -ENOMEM         cannot allocate memory for nodemap
402  */
403 static int nodemap_create(const char *name, bool is_default)
404 {
405         struct  lu_nodemap *nodemap = NULL;
406         int     rc = 0;
407
408         rc = nodemap_lookup(name, &nodemap);
409         if (rc == -EINVAL)
410                 goto out;
411
412         if (rc != -ENOENT) {
413                 nodemap_putref(nodemap);
414                 GOTO(out, rc = -EEXIST);
415         }
416         OBD_ALLOC_PTR(nodemap);
417
418         if (nodemap == NULL) {
419                 CERROR("cannot allocate memory (%zu bytes)"
420                        "for nodemap '%s'\n", sizeof(*nodemap),
421                        name);
422                 GOTO(out, rc = -ENOMEM);
423         }
424
425         snprintf(nodemap->nm_name, sizeof(nodemap->nm_name), "%s", name);
426
427         INIT_LIST_HEAD(&(nodemap->nm_ranges));
428         nodemap->nm_local_to_remote_uidmap = RB_ROOT;
429         nodemap->nm_remote_to_local_uidmap = RB_ROOT;
430         nodemap->nm_local_to_remote_gidmap = RB_ROOT;
431         nodemap->nm_remote_to_local_gidmap = RB_ROOT;
432
433         if (is_default) {
434                 nodemap->nm_id = LUSTRE_NODEMAP_DEFAULT_ID;
435                 nodemap->nmf_trust_client_ids = 0;
436                 nodemap->nmf_allow_root_access = 0;
437                 nodemap->nmf_block_lookups = 0;
438
439                 nodemap->nm_squash_uid = NODEMAP_NOBODY_UID;
440                 nodemap->nm_squash_gid = NODEMAP_NOBODY_GID;
441
442                 lprocfs_nodemap_register(name, is_default, nodemap);
443
444                 default_nodemap = nodemap;
445         } else {
446                 nodemap->nm_id = atomic_inc_return(&nodemap_highest_id);
447                 nodemap->nmf_trust_client_ids =
448                                 default_nodemap->nmf_trust_client_ids;
449                 nodemap->nmf_allow_root_access =
450                                 default_nodemap->nmf_allow_root_access;
451                 nodemap->nmf_block_lookups =
452                                 default_nodemap->nmf_block_lookups;
453
454                 nodemap->nm_squash_uid = default_nodemap->nm_squash_uid;
455                 nodemap->nm_squash_gid = default_nodemap->nm_squash_gid;
456
457                 lprocfs_nodemap_register(name, is_default, nodemap);
458         }
459
460         atomic_set(&nodemap->nm_refcount, 1);
461         rc = cfs_hash_add_unique(nodemap_hash, name, &nodemap->nm_hash);
462
463         if (rc == 0)
464                 goto out;
465
466         CERROR("cannot add nodemap: '%s': rc = %d\n", name, rc);
467         nodemap_destroy(nodemap);
468
469 out:
470         return rc;
471 }
472
473 /*
474  * update flag to turn on or off nodemap functions
475  * \param       name            nodemap name
476  * \param       admin_string    string containing updated value
477  * \retval      0 on success
478  *
479  * Update admin flag to turn on or off nodemap functions.
480  */
481 int nodemap_set_allow_root(const char *name, bool allow_root)
482 {
483         struct lu_nodemap       *nodemap = NULL;
484         int                     rc = 0;
485
486         rc = nodemap_lookup(name, &nodemap);
487         if (nodemap == NULL)
488                 GOTO(out, rc = -ENOENT);
489
490         nodemap->nmf_allow_root_access = allow_root;
491         nodemap_putref(nodemap);
492 out:
493         return rc;
494 }
495 EXPORT_SYMBOL(nodemap_set_allow_root);
496
497 /**
498  * updated trust_client_ids flag for nodemap
499  *
500  * \param       name            nodemap name
501  * \param       trust_string    new value for trust flag
502  * \retval      0 on success
503  *
504  * Update the trust_client_ids flag for a nodemap.
505  */
506 int nodemap_set_trust_client_ids(const char *name, bool trust_client_ids)
507 {
508         struct lu_nodemap       *nodemap = NULL;
509         int                     rc = 0;
510
511         rc = nodemap_lookup(name, &nodemap);
512         if (nodemap == NULL)
513                 GOTO(out, rc = -ENOENT);
514
515         nodemap->nmf_trust_client_ids = trust_client_ids;
516         nodemap_putref(nodemap);
517 out:
518         return rc;
519 }
520 EXPORT_SYMBOL(nodemap_set_trust_client_ids);
521
522 /**
523  * update the squash_uid for a nodemap
524  *
525  * \param       name            nodemap name
526  * \param       uid_string      string containing new squash_uid value
527  * \retval      0 on success
528  *
529  * Update the squash_uid for a nodemap. The squash_uid is the uid
530  * that the all client uids are mapped to if nodemap is active,
531  * the trust_client_ids flag is not set, and the uid is not in
532  * the idmap tree.
533  */
534 int nodemap_set_squash_uid(const char *name, uid_t uid)
535 {
536         struct lu_nodemap       *nodemap = NULL;
537         int                     rc = 0;
538
539         rc = nodemap_lookup(name, &nodemap);
540         if (nodemap == NULL)
541                 GOTO(out, rc = -ENOENT);
542
543         nodemap->nm_squash_uid = uid;
544         nodemap_putref(nodemap);
545 out:
546         return rc;
547 }
548 EXPORT_SYMBOL(nodemap_set_squash_uid);
549
550 /**
551  * update the squash_gid for a nodemap
552  *
553  * \param       name            nodemap name
554  * \param       gid_string      string containing new squash_gid value
555  * \retval      0 on success
556  *
557  * Update the squash_gid for a nodemap. The squash_uid is the gid
558  * that the all client gids are mapped to if nodemap is active,
559  * the trust_client_ids flag is not set, and the gid is not in
560  * the idmap tree.
561  */
562 int nodemap_set_squash_gid(const char *name, gid_t gid)
563 {
564         struct lu_nodemap       *nodemap = NULL;
565         int                     rc = 0;
566
567         rc = nodemap_lookup(name, &nodemap);
568         if (nodemap == NULL)
569                 GOTO(out, rc = -ENOENT);
570
571         nodemap->nm_squash_gid = gid;
572         nodemap_putref(nodemap);
573 out:
574         return rc;
575 }
576 EXPORT_SYMBOL(nodemap_set_squash_gid);
577
578 /**
579  * Add a nodemap
580  *
581  * \param       name            name of nodemap
582  * \retval      0               success
583  * \retval      -EINVAL         invalid nodemap name
584  * \retval      -EEXIST         nodemap already exists
585  * \retval      -ENOMEM         cannot allocate memory for nodemap
586  */
587 int nodemap_add(const char *name)
588 {
589         return nodemap_create(name, 0);
590 }
591 EXPORT_SYMBOL(nodemap_add);
592
593 /**
594  * Delete a nodemap
595  *
596  * \param       name            name of nodemmap
597  * \retval      0               success
598  * \retval      -EINVAL         invalid input
599  * \retval      -ENOENT         no existing nodemap
600  */
601 int nodemap_del(const char *name)
602 {
603         struct  lu_nodemap *nodemap;
604         int     rc = 0;
605
606         if (strcmp(name, DEFAULT_NODEMAP) == 0)
607                 GOTO(out, rc = -EINVAL);
608
609         nodemap = cfs_hash_del_key(nodemap_hash, name);
610         if (nodemap == NULL)
611                 GOTO(out, rc = -ENOENT);
612
613         nodemap_putref(nodemap);
614 out:
615         return rc;
616 }
617 EXPORT_SYMBOL(nodemap_del);
618
619 /**
620  * Cleanup nodemap module on exit
621  */
622 static void nodemap_mod_exit(void)
623 {
624         nodemap_cleanup_all();
625         lprocfs_remove(&proc_lustre_nodemap_root);
626 }
627
628 /**
629  * Initialize the nodemap module
630  */
631 static int __init nodemap_mod_init(void)
632 {
633         int rc = 0;
634
635         rc = nodemap_init_hash();
636         if (rc != 0)
637                 goto cleanup;
638
639         nodemap_procfs_init();
640         rc = nodemap_create(DEFAULT_NODEMAP, 1);
641
642 cleanup:
643         if (rc != 0)
644                 nodemap_mod_exit();
645
646         return rc;
647 }
648
649 MODULE_LICENSE("GPL");
650 MODULE_DESCRIPTION("Lustre Client Nodemap Management Module");
651 MODULE_AUTHOR("Joshua Walgenbach <jjw@iu.edu>");
652
653 module_init(nodemap_mod_init);
654 module_exit(nodemap_mod_exit);