Whamcloud - gitweb
LU-4647 nodemap: add mapping functionality
[fs/lustre-release.git] / lustre / ptlrpc / nodemap_lproc.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
27 #define NODEMAP_LPROC_ID_LEN 16
28 #define NODEMAP_LPROC_FLAG_LEN 2
29
30 #include <lprocfs_status.h>
31 #include <lustre_net.h>
32 #include <lustre_export.h>
33 #include <obd_class.h>
34 #include <interval_tree.h>
35 #include "nodemap_internal.h"
36
37 /* Turn on proc debug interface to allow OSS and
38  * MDS nodes to configure nodemap independently of
39  * MGS (since the nodemap distribution is not written
40  * yet */
41 #define NODEMAP_PROC_DEBUG 1
42
43 /**
44  * Reads and prints the idmap for the given nodemap.
45  *
46  * \param       m               seq file in proc fs
47  * \param       data            unused
48  * \retval      0               success
49  */
50 static int nodemap_idmap_show(struct seq_file *m, void *data)
51 {
52         struct lu_nodemap       *nodemap = m->private;
53         struct lu_idmap         *idmap;
54         struct rb_node          *node;
55         bool                    cont = 0;
56
57         seq_printf(m, "[\n");
58         read_lock(&nodemap->nm_idmap_lock);
59         for (node = rb_first(&nodemap->nm_client_to_fs_uidmap); node;
60                                 node = rb_next(node)) {
61                 if (cont)
62                         seq_printf(m, ",\n");
63                 cont = 1;
64                 idmap = rb_entry(node, struct lu_idmap, id_client_to_fs);
65                 if (idmap != NULL)
66                         seq_printf(m, " { idtype: uid, client_id: %u, "
67                                    "fs_id: %u }", idmap->id_client,
68                                    idmap->id_fs);
69         }
70         for (node = rb_first(&nodemap->nm_client_to_fs_gidmap);
71                                 node; node = rb_next(node)) {
72                 if (cont)
73                         seq_printf(m, ",\n");
74                 idmap = rb_entry(node, struct lu_idmap, id_client_to_fs);
75                 if (idmap != NULL)
76                         seq_printf(m, " { idtype: gid, client_id: %u, "
77                                    "fs_id: %u }", idmap->id_client,
78                                    idmap->id_fs);
79         }
80         read_unlock(&nodemap->nm_idmap_lock);
81         seq_printf(m, "\n");
82         seq_printf(m, "]\n");
83
84         return 0;
85 }
86
87 /**
88  * Attaches nodemap_idmap_show to proc file.
89  *
90  * \param       inode           inode of seq file in proc fs
91  * \param       file            seq file
92  * \retval      0               success
93  */
94 static int nodemap_idmap_open(struct inode *inode, struct file *file)
95 {
96         struct lu_nodemap *nodemap = PDE_DATA(inode);
97
98         return single_open(file, nodemap_idmap_show, nodemap);
99 }
100
101 /**
102  * Reads and prints the NID ranges for the given nodemap.
103  *
104  * \param       m               seq file in proc fs
105  * \param       data            unused
106  * \retval      0               success
107  */
108 static int nodemap_ranges_show(struct seq_file *m, void *data)
109 {
110         struct lu_nodemap               *nodemap = m->private;
111         struct lu_nid_range             *range;
112         struct interval_node_extent     ext;
113         bool                            cont = false;
114
115         seq_printf(m, "[\n");
116         read_lock(&nm_range_tree_lock);
117         list_for_each_entry(range, &nodemap->nm_ranges, rn_list) {
118                 if (cont)
119                         seq_printf(m, ",\n");
120                 cont = 1;
121                 ext = range->rn_node.in_extent;
122                 seq_printf(m, " { id: %u, start_nid: %s, "
123                                 "end_nid: %s }",
124                            range->rn_id, libcfs_nid2str(ext.start),
125                            libcfs_nid2str(ext.end));
126         }
127         read_unlock(&nm_range_tree_lock);
128         seq_printf(m, "\n");
129         seq_printf(m, "]\n");
130
131         return 0;
132 }
133
134 /**
135  * Connects nodemap_idmap_show to proc file.
136  *
137  * \param       inode           inode of seq file in proc fs
138  * \param       file            seq file
139  * \retval      0               success
140  */
141 static int nodemap_ranges_open(struct inode *inode, struct file *file)
142 {
143         struct lu_nodemap *nodemap = PDE_DATA(inode);
144
145         return single_open(file, nodemap_ranges_show, nodemap);
146 }
147
148 /**
149  * Hash callback, reads and prints the exports attached to this nodemap.
150  *
151  * \param       hs              nodemap member hash
152  * \param       bd              unused
153  * \param       hnode           current member in hash
154  * \param       data            seq_file to print to
155  * \retval      0               success
156  */
157 static int nodemap_exports_show_cb(cfs_hash_t *hs, cfs_hash_bd_t *bd,
158                                    struct hlist_node *hnode, void *data)
159 {
160         struct seq_file         *m = data;
161         struct obd_export       *exp;
162         char                    *key;
163
164         exp = hlist_entry(hnode, struct obd_export,
165                           exp_target_data.ted_nodemap_member);
166         key = cfs_hash_key(hs, hnode);
167         seq_printf(m, " { nid: %s, uuid: %s },",
168                    obd_export_nid2str(exp), exp->exp_client_uuid.uuid);
169
170         return 0;
171 }
172
173 /**
174  * Reads and prints the exports attached to the given nodemap via hash
175  * foreach callback.
176  *
177  * \param       m               seq file in proc fs
178  * \param       data            unused
179  * \retval      0               success
180  */
181 static int nodemap_exports_show(struct seq_file *m, void *data)
182 {
183         struct lu_nodemap               *nodemap = m->private;
184
185         seq_printf(m, "[\n");
186
187         cfs_hash_for_each(nodemap->nm_member_hash, nodemap_exports_show_cb, m);
188
189         seq_printf(m, "\n");
190         seq_printf(m, "]\n");
191
192         return 0;
193 }
194
195 /**
196  * Attaches nodemap_idmap_show to proc file.
197  *
198  * \param       inode           inode of seq file in proc fs
199  * \param       file            seq file
200  * \retval      0               success
201  */
202 static int nodemap_exports_open(struct inode *inode, struct file *file)
203 {
204         struct proc_dir_entry   *dir = PDE(inode);
205         struct lu_nodemap       *nodemap = dir->data;
206
207         return single_open(file, nodemap_exports_show, nodemap);
208 }
209
210 /**
211  * Reads and prints the active flag for the given nodemap.
212  *
213  * \param       m               seq file in proc fs
214  * \param       data            unused
215  * \retval      0               success
216  */
217 static int nodemap_active_seq_show(struct seq_file *m, void *data)
218 {
219         return seq_printf(m, "%u\n", (unsigned int)nodemap_active);
220 }
221
222 /**
223  * Activate/deactivate nodemap.
224  *
225  * \param[in] file      proc file
226  * \param[in] buffer    string, "1" or "0" to activate/deactivate nodemap
227  * \param[in] count     \a buffer length
228  * \param[in] off       unused
229  * \retval              \a count on success
230  * \retval              negative number on error
231  */
232 static ssize_t
233 nodemap_active_seq_write(struct file *file, const char __user *buffer,
234                          size_t count, loff_t *off)
235 {
236         char                    active_string[NODEMAP_LPROC_FLAG_LEN + 1];
237         long unsigned int       active;
238         int                     rc;
239
240         if (count == 0)
241                 return 0;
242
243         if (count >= sizeof(active_string))
244                 return -EINVAL;
245
246         if (copy_from_user(active_string, buffer, count))
247                 return -EFAULT;
248
249         active_string[count] = '\0';
250         rc = kstrtoul(active_string, 10, &active);
251         if (rc != 0)
252                 return -EINVAL;
253
254         nodemap_active = active;
255
256         return count;
257 }
258 LPROC_SEQ_FOPS(nodemap_active);
259
260 /**
261  * Reads and prints the nodemap ID for the given nodemap.
262  *
263  * \param       m               seq file in proc fs
264  * \param       data            unused
265  * \retval      0               success
266  */
267 static int nodemap_id_seq_show(struct seq_file *m, void *data)
268 {
269         struct lu_nodemap *nodemap = m->private;
270
271         return seq_printf(m, "%u\n", nodemap->nm_id);
272 }
273 LPROC_SEQ_FOPS_RO(nodemap_id);
274
275 /**
276  * Reads and prints the root squash UID for the given nodemap.
277  *
278  * \param       m               seq file in proc fs
279  * \param       data            unused
280  * \retval      0               success
281  */
282 static int nodemap_squash_uid_seq_show(struct seq_file *m, void *data)
283 {
284         struct lu_nodemap *nodemap = m->private;
285
286         return seq_printf(m, "%u\n", nodemap->nm_squash_uid);
287 }
288
289 /**
290  * Reads and prints the root squash GID for the given nodemap.
291  *
292  * \param       m               seq file in proc fs
293  * \param       data            unused
294  * \retval      0               success
295  */
296 static int nodemap_squash_gid_seq_show(struct seq_file *m, void *data)
297 {
298         struct lu_nodemap *nodemap = m->private;
299
300         return seq_printf(m, "%u\n", nodemap->nm_squash_gid);
301 }
302
303 /**
304  * Reads and prints the trusted flag for the given nodemap.
305  *
306  * \param       m               seq file in proc fs
307  * \param       data            unused
308  * \retval      0               success
309  */
310 static int nodemap_trusted_seq_show(struct seq_file *m, void *data)
311 {
312         struct lu_nodemap *nodemap = m->private;
313
314         return seq_printf(m, "%d\n", (int)nodemap->nmf_trust_client_ids);
315 }
316
317 /**
318  * Reads and prints the admin flag for the given nodemap.
319  *
320  * \param       m               seq file in proc fs
321  * \param       data            unused
322  * \retval      0               success
323  */
324 static int nodemap_admin_seq_show(struct seq_file *m, void *data)
325 {
326         struct lu_nodemap *nodemap = m->private;
327
328         return seq_printf(m, "%d\n", (int)nodemap->nmf_allow_root_access);
329 }
330
331 #ifdef NODEMAP_PROC_DEBUG
332 /**
333  * Helper functions to set nodemap flags.
334  *
335  * \param[in] buffer    string, which is "1" or "0" to set/unset flag
336  * \param[in] count     \a buffer length
337  * \param[out] flag_p   where to store flag value
338  * \retval              \a count on success
339  * \retval              negative number on error
340  */
341 static int nodemap_proc_read_flag(const char __user *buffer,
342                                   unsigned long count, unsigned int *flag_p)
343 {
344         char                    scratch[NODEMAP_LPROC_FLAG_LEN + 1];
345         long unsigned int       flag_buf;
346         int                     rc;
347
348         if (count == 0)
349                 return 0;
350
351         if (count >= sizeof(scratch))
352                 return -EINVAL;
353
354         if (copy_from_user(scratch, buffer, count))
355                 return -EFAULT;
356
357         scratch[count] = '\0';
358         rc = kstrtoul(scratch, 10, &flag_buf);
359         if (rc != 0)
360                 return -EINVAL;
361
362         *flag_p = flag_buf;
363
364         return count;
365 }
366
367 /**
368  * Set the squash UID.
369  *
370  * \param[in] file      proc file
371  * \param[in] buffer    string representing squash UID to set
372  * \param[in] count     \a buffer length
373  * \param[in] off       unused
374  * \retval              \a count on success
375  * \retval              negative number on error
376  */
377 static ssize_t
378 nodemap_squash_uid_seq_write(struct file *file, const char __user *buffer,
379                              size_t count, loff_t *off)
380 {
381         char                     squash[NODEMAP_LPROC_ID_LEN + 1];
382         struct seq_file         *m = file->private_data;
383         struct lu_nodemap       *nodemap = m->private;
384         long unsigned int        squash_uid;
385         int                      rc;
386
387         if (count == 0)
388                 return 0;
389
390         if (count >= sizeof(squash))
391                 return -EINVAL;
392
393         if (copy_from_user(squash, buffer, count))
394                 return -EFAULT;
395
396         squash[count] = '\0';
397         rc = kstrtoul(squash, 10, &squash_uid);
398         if (rc != 0)
399                 return -EINVAL;
400
401         nodemap->nm_squash_uid = squash_uid;
402
403         return count;
404 }
405
406 /**
407  * Set the squash GID.
408  *
409  * \param[in] file      proc file
410  * \param[in] buffer    string representing squash GID to set
411  * \param[in] count     \a buffer length
412  * \param[in] off       unused
413  * \retval              \a count on success
414  * \retval              negative number on error
415  */
416 static ssize_t
417 nodemap_squash_gid_seq_write(struct file *file, const char __user *buffer,
418                              size_t count, loff_t *off)
419 {
420         char                     squash[NODEMAP_LPROC_ID_LEN + 1];
421         struct seq_file         *m = file->private_data;
422         struct lu_nodemap       *nodemap = m->private;
423         long unsigned int        squash_gid;
424         int                      rc;
425
426         if (count == 0)
427                 return 0;
428
429         if (count >= sizeof(squash))
430                 return -EINVAL;
431
432         if (copy_from_user(squash, buffer, count))
433                 return -EFAULT;
434
435         squash[count] = '\0';
436         rc = kstrtoul(squash, 10, &squash_gid);
437         if (rc != 0)
438                 return -EINVAL;
439
440         nodemap->nm_squash_gid = squash_gid;
441
442         return count;
443 }
444
445 /**
446  * Set/unset the trusted flag.
447  *
448  * \param[in] file      proc file
449  * \param[in] buffer    string, "1" or "0"
450  * \param[in] count     \a buffer length
451  * \param[in] off       unused
452  * \retval              \a count on success
453  * \retval              negative number on error
454  */
455 static ssize_t
456 nodemap_trusted_seq_write(struct file *file, const char __user *buffer,
457                           size_t count, loff_t *off)
458 {
459         struct seq_file         *m = file->private_data;
460         struct lu_nodemap       *nodemap = m->private;
461         int                     flags;
462         int                     rc;
463
464         rc = nodemap_proc_read_flag(buffer, count, &flags);
465         if (rc >= 0) {
466                 nodemap->nmf_trust_client_ids = !!flags;
467                 nm_member_revoke_locks(nodemap);
468         }
469
470         return rc;
471 }
472
473 /**
474  * Set/unset the admin flag.
475  *
476  * \param[in] file      proc file
477  * \param[in] buffer    string, "1" or "0"
478  * \param[in] count     \a buffer length
479  * \param[in] off       unused
480  * \retval              \a count on success
481  * \retval              negative number on error
482  */
483 static ssize_t
484 nodemap_admin_seq_write(struct file *file, const char __user *buffer,
485                         size_t count, loff_t *off)
486 {
487         struct seq_file         *m = file->private_data;
488         struct lu_nodemap       *nodemap = m->private;
489         int                     flags;
490         int                     rc;
491
492         rc = nodemap_proc_read_flag(buffer, count, &flags);
493         if (rc >= 0) {
494                 nodemap->nmf_allow_root_access = !!flags;
495                 nm_member_revoke_locks(nodemap);
496         }
497
498         return rc;
499 }
500
501 /**
502  * Add a nodemap.
503  *
504  * \param[in] file      proc file
505  * \param[in] buffer    string, name of the nodemap to add
506  * \param[in] count     \a buffer length
507  * \param[in] off       unused
508  * \retval              \a count on success
509  * \retval              negative number on error
510  */
511 static ssize_t
512 lprocfs_add_nodemap_seq_write(struct file *file, const char __user *buffer,
513                               size_t count, loff_t *off)
514 {
515         char    nodemap_name[LUSTRE_NODEMAP_NAME_LENGTH + 1];
516         char    *cpybuf = NULL;
517         char    *pos;
518         int     rc;
519
520         if (count == 0)
521                 return 0;
522
523         if (count >= sizeof(nodemap_name))
524                 return -EINVAL;
525
526         if (copy_from_user(nodemap_name, buffer, count))
527                 return -EFAULT;
528
529         nodemap_name[count] = '\0';
530
531         cpybuf = nodemap_name;
532         pos = strsep(&cpybuf, " \n");
533         if (pos == NULL)
534                 return -EINVAL;
535
536         rc = nodemap_add(nodemap_name);
537         if (rc == 0)
538                 rc = count;
539
540         return rc;
541 }
542 LPROC_SEQ_FOPS_WO_TYPE(nodemap, add_nodemap);
543
544 /**
545  * Delete a nodemap.
546  *
547  * \param[in] file      proc file
548  * \param[in] buffer    string, name of the nodemap to delete
549  * \param[in] count     \a buffer length
550  * \param[in] off       unused
551  * \retval              \a count on success
552  * \retval              negative number on error
553  */
554 static ssize_t
555 lprocfs_del_nodemap_seq_write(struct file *file, const char __user *buffer,
556                               size_t count, loff_t *off)
557 {
558         char    nodemap_name[LUSTRE_NODEMAP_NAME_LENGTH + 1];
559         char    *cpybuf = NULL;
560         char    *pos;
561         int     rc = count;
562
563         if (count == 0)
564                 return 0;
565
566         if (count >= sizeof(nodemap_name))
567                 return -EINVAL;
568
569         if (copy_from_user(nodemap_name, buffer, count))
570                 return -EFAULT;
571
572         nodemap_name[count] = '\0';
573
574         cpybuf = nodemap_name;
575         pos = strsep(&cpybuf, " \n");
576         if (pos == NULL)
577                 return -EINVAL;
578
579         rc = nodemap_del(nodemap_name);
580         if (rc == 0)
581                 rc = count;
582
583         return rc;
584
585 }
586 LPROC_SEQ_FOPS_WO_TYPE(nodemap, del_nodemap);
587
588 /**
589  * Helper function to parse a NID string.
590  *
591  * \param[in] rangestr  string representation of NIDs, see libcfs_str2nid()
592  * \param[out] nids     array of two nids
593  * \retval              0 on success
594  * \retval              negative number on error
595  */
596 static int parse_nids(char *rangestr, lnet_nid_t nids[2])
597 {
598         struct list_head        nidlist;
599         char                    nidstr[2][LNET_NIDSTR_SIZE];
600         char                    nidrange_str[2 * LNET_NIDSTR_SIZE + 2];
601         int                     rc = 0;
602
603         INIT_LIST_HEAD(&nidlist);
604
605         if (cfs_parse_nidlist(rangestr, strlen(rangestr),
606             &nidlist) <= 0)
607                 return -EINVAL;
608
609         if (!cfs_nidrange_is_contiguous(&nidlist))
610                 return -EINVAL;
611
612         cfs_nidrange_find_min_max(&nidlist, nidstr[0], nidstr[1],
613                                   LNET_NIDSTR_SIZE);
614         snprintf(nidrange_str, sizeof(nidrange_str), "%s:%s",
615                 nidstr[0], nidstr[1]);
616
617         rc = nodemap_parse_range(nidrange_str, nids);
618         if (rc != 0)
619                 return -EINVAL;
620
621         cfs_free_nidlist(&nidlist);
622
623         return 0;
624 }
625
626 /**
627  * Add a NID range to nodemap.
628  *
629  * \param[in] file      proc file
630  * \param[in] buffer    string, "<nodemap name> <nid range>"
631  * \param[in] count     \a buffer length
632  * \param[in] off       unused
633  * \retval              \a count on success
634  * \retval              negative number on error
635  */
636 static ssize_t
637 lprocfs_add_nodemap_range_seq_write(struct file *file,
638                                     const char __user *buffer,
639                                     size_t count, loff_t *off)
640 {
641         char                    name_range[LUSTRE_NODEMAP_NAME_LENGTH +
642                                            LNET_NIDSTR_SIZE * 2 + 2];
643         char                    *cpybuf = NULL;
644         char                    *name;
645         char                    *rangestr = NULL;
646         lnet_nid_t              nids[2];
647         int                     rc;
648
649         if (count == 0)
650                 return 0;
651
652         if (count >= sizeof(name_range))
653                 GOTO(out, rc = -EINVAL);
654
655         if (copy_from_user(name_range, buffer, count))
656                 GOTO(out, rc = -EFAULT);
657
658         name_range[count] = '\0';
659
660         cpybuf = name_range;
661         name = strsep(&cpybuf, " ");
662         if (name == NULL)
663                 GOTO(out, rc = -EINVAL);
664
665         rangestr = strsep(&cpybuf, " \n");
666         if (rangestr == NULL)
667                 GOTO(out, rc = -EINVAL);
668
669         rc = parse_nids(rangestr, nids);
670         if (rc != 0)
671                 GOTO(out, rc = rc);
672
673         rc = nodemap_add_range(name, nids);
674         if (rc != 0)
675                 GOTO(out, rc = -EINVAL);
676
677         if (rc == 0)
678                 rc = count;
679
680 out:
681         return rc;
682 }
683 LPROC_SEQ_FOPS_WO_TYPE(nodemap, add_nodemap_range);
684
685 /**
686  * Delete a NID range from nodemap.
687  *
688  * \param[in] file      proc file
689  * \param[in] buffer    string, "<nodemap name> <nid range>"
690  * \param[in] count     \a buffer length
691  * \param[in] off       unused
692  * \retval              \a count on success
693  * \retval              negative number on error
694  */
695 static ssize_t
696 lprocfs_del_nodemap_range_seq_write(struct file *file,
697                                     const char __user *buffer,
698                                     size_t count, loff_t *off)
699 {
700         char                    name_range[LUSTRE_NODEMAP_NAME_LENGTH +
701                                            LNET_NIDSTR_SIZE * 2 + 2];
702         char                    *cpybuf = NULL;
703         char                    *name;
704         char                    *rangestr = NULL;
705         lnet_nid_t              nids[2];
706         int                     rc;
707
708         if (count == 0)
709                 return 0;
710
711         if (count >= sizeof(name_range))
712                 GOTO(out, rc = -EINVAL);
713
714         if (copy_from_user(name_range, buffer, count))
715                 GOTO(out, rc = -EFAULT);
716
717         name_range[count] = '\0';
718
719         cpybuf = name_range;
720         name = strsep(&cpybuf, " ");
721         if (name == NULL)
722                 GOTO(out, rc = -EINVAL);
723
724         rangestr = strsep(&cpybuf, " \n");
725         if (rangestr == NULL)
726                 GOTO(out, rc = -EINVAL);
727
728         rc = parse_nids(rangestr, nids);
729         if (rc != 0)
730                 GOTO(out, rc = rc);
731
732         rc = nodemap_del_range(name, nids);
733         if (rc != 0)
734                 GOTO(out, rc = -EINVAL);
735
736         if (rc == 0)
737                 rc = count;
738
739 out:
740         return rc;
741 }
742 LPROC_SEQ_FOPS_WO_TYPE(nodemap, del_nodemap_range);
743
744 /**
745  * Add an idmap to nodemap.
746  *
747  * \param[in] file      proc file
748  * \param[in] buffer    string, "<nodemap name> <uid|gid> <idmap>"
749  * \param[in] count     \a buffer length
750  * \param[in] off       unused
751  * \retval              \a count on success
752  * \retval              negative number on error
753  */
754 static ssize_t
755 lprocfs_add_nodemap_idmap_seq_write(struct file *file,
756                                     const char __user *buffer,
757                                     size_t count, loff_t *off)
758 {
759         char                    name_idmapstr[LUSTRE_NODEMAP_NAME_LENGTH + 16];
760         char                    *cpybuf = NULL;
761         char                    *name;
762         char                    *idtypestr = NULL;
763         char                    *idmapstr = NULL;
764         __u32                   idmap[2];
765         int                     rc = count;
766
767         if (count == 0)
768                 return 0;
769
770         if (count >= sizeof(name_idmapstr))
771                 GOTO(out, rc = -EINVAL);
772
773         if (copy_from_user(name_idmapstr, buffer, count))
774                 GOTO(out, rc = -EFAULT);
775
776         name_idmapstr[count] = '\0';
777
778         cpybuf = name_idmapstr;
779         name = strsep(&cpybuf, " ");
780         if (name == NULL)
781                 GOTO(out, rc = -EINVAL);
782
783         idtypestr = strsep(&cpybuf, " ");
784         if (idtypestr == NULL)
785                 GOTO(out, rc = -EINVAL);
786
787         idmapstr = strsep(&cpybuf, " \n");
788         if (idmapstr == NULL)
789                 GOTO(out, rc = -EINVAL);
790
791         rc = nodemap_parse_idmap(idmapstr, idmap);
792         if (rc != 0)
793                 GOTO(out, rc = -EINVAL);
794
795         if (strcmp(idtypestr, "uid") == 0)
796                 rc = nodemap_add_idmap(name, NODEMAP_UID, idmap);
797         else if (strcmp(idtypestr, "gid") == 0)
798                 rc = nodemap_add_idmap(name, NODEMAP_GID, idmap);
799         else
800                 GOTO(out, rc = -EINVAL);
801
802         if (rc != 0)
803                 GOTO(out, rc = -EINVAL);
804
805         if (rc == 0)
806                 rc = count;
807
808 out:
809         return rc;
810 }
811 LPROC_SEQ_FOPS_WO_TYPE(nodemap, add_nodemap_idmap);
812
813 /**
814  * Delete an idmap from nodemap.
815  *
816  * \param[in] file      proc file
817  * \param[in] buffer    string, "<nodemap name> <uid|gid> <idmap>"
818  * \param[in] count     \a buffer length
819  * \param[in] off       unused
820  * \retval              \a count on success
821  * \retval              negative number on error
822  */
823 static ssize_t
824 lprocfs_del_nodemap_idmap_seq_write(struct file *file,
825                                     const char __user *buffer,
826                                     size_t count, loff_t *off)
827 {
828         char                    name_idmapstr[LUSTRE_NODEMAP_NAME_LENGTH + 16];
829         char                    *cpybuf = NULL;
830         char                    *name;
831         char                    *idtypestr = NULL;
832         char                    *idmapstr = NULL;
833         __u32                   idmap[2];
834         int                     rc = count;
835
836         if (count == 0)
837                 return 0;
838
839         if (count >= sizeof(name_idmapstr))
840                 GOTO(out, rc = -EINVAL);
841
842         if (copy_from_user(name_idmapstr, buffer, count))
843                 GOTO(out, rc = -EFAULT);
844
845         name_idmapstr[count] = '\0';
846
847         cpybuf = name_idmapstr;
848         name = strsep(&cpybuf, " ");
849         if (name == NULL)
850                 GOTO(out, rc = -EINVAL);
851
852         idtypestr = strsep(&cpybuf, " ");
853         if (idtypestr == NULL)
854                 GOTO(out, rc = -EINVAL);
855
856         idmapstr = strsep(&cpybuf, " \n");
857         if (idmapstr == NULL)
858                 GOTO(out, rc = -EINVAL);
859
860         rc = nodemap_parse_idmap(idmapstr, idmap);
861         if (rc != 0)
862                 GOTO(out, rc = -EINVAL);
863
864         if (strcmp(idtypestr, "uid") == 0)
865                 rc = nodemap_del_idmap(name, NODEMAP_UID, idmap);
866         else if (strcmp(idtypestr, "gid") == 0)
867                 rc = nodemap_del_idmap(name, NODEMAP_GID, idmap);
868         else
869                 GOTO(out, rc = -EINVAL);
870
871         if (rc != 0)
872                 GOTO(out, rc = -EINVAL);
873
874         if (rc == 0)
875                 rc = count;
876
877 out:
878         return rc;
879 }
880 LPROC_SEQ_FOPS_WO_TYPE(nodemap, del_nodemap_idmap);
881 #endif /* NODEMAP_PROC_DEBUG */
882
883 static struct lprocfs_seq_vars lprocfs_nm_module_vars[] = {
884         {
885                 .name           = "active",
886                 .fops           = &nodemap_active_fops,
887         },
888 #ifdef NODEMAP_PROC_DEBUG
889         {
890                 .name           = "add_nodemap",
891                 .fops           = &nodemap_add_nodemap_fops,
892         },
893         {
894                 .name           = "remove_nodemap",
895                 .fops           = &nodemap_del_nodemap_fops,
896         },
897         {
898                 .name           = "add_nodemap_range",
899                 .fops           = &nodemap_add_nodemap_range_fops,
900         },
901         {
902                 .name           = "del_nodemap_range",
903                 .fops           = &nodemap_del_nodemap_range_fops,
904         },
905         {
906                 .name           = "add_nodemap_idmap",
907                 .fops           = &nodemap_add_nodemap_idmap_fops,
908         },
909         {
910                 .name           = "del_nodemap_idmap",
911                 .fops           = &nodemap_del_nodemap_idmap_fops,
912         },
913 #endif /* NODEMAP_PROC_DEBUG */
914         {
915                 NULL
916         }
917 };
918
919 #ifdef NODEMAP_PROC_DEBUG
920 LPROC_SEQ_FOPS(nodemap_trusted);
921 LPROC_SEQ_FOPS(nodemap_admin);
922 LPROC_SEQ_FOPS(nodemap_squash_uid);
923 LPROC_SEQ_FOPS(nodemap_squash_gid);
924 #else
925 LPROC_SEQ_FOPS_RO(nodemap_trusted);
926 LPROC_SEQ_FOPS_RO(nodemap_admin);
927 LPROC_SEQ_FOPS_RO(nodemap_squash_uid);
928 LPROC_SEQ_FOPS_RO(nodemap_squash_gid);
929 #endif
930
931 const struct file_operations nodemap_ranges_fops = {
932         .open                   = nodemap_ranges_open,
933         .read                   = seq_read,
934         .llseek                 = seq_lseek,
935         .release                = single_release
936 };
937
938 const struct file_operations nodemap_idmap_fops = {
939         .open                   = nodemap_idmap_open,
940         .read                   = seq_read,
941         .llseek                 = seq_lseek,
942         .release                = single_release
943 };
944
945 const struct file_operations nodemap_exports_fops = {
946         .open                   = nodemap_exports_open,
947         .read                   = seq_read,
948         .llseek                 = seq_lseek,
949         .release                = single_release
950 };
951
952 static struct lprocfs_seq_vars lprocfs_nodemap_vars[] = {
953         {
954                 .name           = "id",
955                 .fops           = &nodemap_id_fops,
956         },
957         {
958                 .name           = "trusted_nodemap",
959                 .fops           = &nodemap_trusted_fops,
960         },
961         {
962                 .name           = "admin_nodemap",
963                 .fops           = &nodemap_admin_fops,
964         },
965         {
966                 .name           = "squash_uid",
967                 .fops           = &nodemap_squash_uid_fops,
968         },
969         {
970                 .name           = "squash_gid",
971                 .fops           = &nodemap_squash_gid_fops,
972         },
973         {
974                 .name           = "ranges",
975                 .fops           = &nodemap_ranges_fops,
976         },
977         {
978                 .name           = "exports",
979                 .fops           = &nodemap_exports_fops,
980         },
981         {
982                 .name           = "idmap",
983                 .fops           = &nodemap_idmap_fops,
984         },
985         {
986                 NULL
987         }
988 };
989
990 static struct lprocfs_seq_vars lprocfs_default_nodemap_vars[] = {
991         {
992                 .name           = "id",
993                 .fops           = &nodemap_id_fops,
994         },
995         {
996                 .name           = "trusted_nodemap",
997                 .fops           = &nodemap_trusted_fops,
998         },
999         {
1000                 .name           = "admin_nodemap",
1001                 .fops           = &nodemap_admin_fops,
1002         },
1003         {
1004                 .name           = "squash_uid",
1005                 .fops           = &nodemap_squash_uid_fops,
1006         },
1007         {
1008                 .name           = "squash_gid",
1009                 .fops           = &nodemap_squash_gid_fops,
1010         },
1011         {
1012                 .name           = "exports",
1013                 .fops           = &nodemap_exports_fops,
1014         },
1015         {
1016                 NULL
1017         }
1018 };
1019
1020 /**
1021  * Initialize the nodemap procfs directory.
1022  *
1023  * \retval      0               success
1024  */
1025 int nodemap_procfs_init(void)
1026 {
1027         int rc = 0;
1028
1029         proc_lustre_nodemap_root = lprocfs_seq_register(LUSTRE_NODEMAP_NAME,
1030                                                         proc_lustre_root,
1031                                                         lprocfs_nm_module_vars,
1032                                                         NULL);
1033
1034         if (IS_ERR(proc_lustre_nodemap_root)) {
1035                 rc = PTR_ERR(proc_lustre_nodemap_root);
1036                 CERROR("cannot create 'nodemap' directory: rc = %d\n",
1037                        rc);
1038                 proc_lustre_nodemap_root = NULL;
1039         }
1040
1041         return rc;
1042 }
1043
1044 /**
1045  * Register the proc directory for a nodemap
1046  *
1047  * \param       name            name of nodemap
1048  * \param       is_default:     1 if default nodemap
1049  * \retval      0               success
1050  */
1051 int lprocfs_nodemap_register(const char *name,
1052                              bool is_default,
1053                              struct lu_nodemap *nodemap)
1054 {
1055         struct proc_dir_entry   *nodemap_proc_entry;
1056         int                     rc = 0;
1057
1058         if (is_default)
1059                 nodemap_proc_entry =
1060                         lprocfs_seq_register(name,
1061                                              proc_lustre_nodemap_root,
1062                                              lprocfs_default_nodemap_vars,
1063                                              nodemap);
1064         else
1065                 nodemap_proc_entry =
1066                         lprocfs_seq_register(name,
1067                                              proc_lustre_nodemap_root,
1068                                              lprocfs_nodemap_vars,
1069                                              nodemap);
1070
1071         if (IS_ERR(nodemap_proc_entry)) {
1072                 rc = PTR_ERR(nodemap_proc_entry);
1073                 CERROR("cannot create 'nodemap/%s': rc = %d\n", name, rc);
1074                 nodemap_proc_entry = NULL;
1075         }
1076
1077         nodemap->nm_proc_entry = nodemap_proc_entry;
1078
1079         return rc;
1080 }