Whamcloud - gitweb
c38478575c3c289667ca8b452b602c5381cabd68
[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  *
25  * Copyright (c) 2014, 2015, Intel Corporation.
26  *
27  * Author: Joshua Walgenbach <jjw@iu.edu>
28  */
29
30 #define NODEMAP_LPROC_ID_LEN 16
31 #define NODEMAP_LPROC_FLAG_LEN 2
32
33 #include <lprocfs_status.h>
34 #include <lustre_net.h>
35 #include <lustre_export.h>
36 #include <obd_class.h>
37 #include <interval_tree.h>
38 #include "nodemap_internal.h"
39
40 static LIST_HEAD(nodemap_pde_list);
41
42 /**
43  * Reads and prints the idmap for the given nodemap.
44  *
45  * \param       m               seq file in proc fs
46  * \param       data            unused
47  * \retval      0               success
48  */
49 static int nodemap_idmap_show(struct seq_file *m, void *data)
50 {
51         struct lu_nodemap       *nodemap;
52         struct lu_idmap         *idmap;
53         struct rb_node          *node;
54         bool                    cont = 0;
55         int rc;
56
57         mutex_lock(&active_config_lock);
58         nodemap = nodemap_lookup(m->private);
59         mutex_unlock(&active_config_lock);
60         if (IS_ERR(nodemap)) {
61                 rc = PTR_ERR(nodemap);
62                 CERROR("cannot find nodemap '%s': rc = %d\n",
63                         (char *)m->private, rc);
64                 return rc;
65         }
66
67         seq_printf(m, "[\n");
68         read_lock(&nodemap->nm_idmap_lock);
69         for (node = rb_first(&nodemap->nm_client_to_fs_uidmap); node;
70                                 node = rb_next(node)) {
71                 if (cont)
72                         seq_printf(m, ",\n");
73                 cont = 1;
74                 idmap = rb_entry(node, struct lu_idmap, id_client_to_fs);
75                 if (idmap != NULL)
76                         seq_printf(m, " { idtype: uid, client_id: %u, "
77                                    "fs_id: %u }", idmap->id_client,
78                                    idmap->id_fs);
79         }
80         for (node = rb_first(&nodemap->nm_client_to_fs_gidmap);
81                                 node; node = rb_next(node)) {
82                 if (cont)
83                         seq_printf(m, ",\n");
84                 idmap = rb_entry(node, struct lu_idmap, id_client_to_fs);
85                 if (idmap != NULL)
86                         seq_printf(m, " { idtype: gid, client_id: %u, "
87                                    "fs_id: %u }", idmap->id_client,
88                                    idmap->id_fs);
89         }
90         read_unlock(&nodemap->nm_idmap_lock);
91         seq_printf(m, "\n");
92         seq_printf(m, "]\n");
93
94         nodemap_putref(nodemap);
95         return 0;
96 }
97
98 /**
99  * Attaches nodemap_idmap_show to proc file.
100  *
101  * \param       inode           inode of seq file in proc fs
102  * \param       file            seq file
103  * \retval      0               success
104  */
105 static int nodemap_idmap_open(struct inode *inode, struct file *file)
106 {
107         return single_open(file, nodemap_idmap_show, PDE_DATA(inode));
108 }
109
110 /**
111  * Reads and prints the NID ranges for the given nodemap.
112  *
113  * \param       m               seq file in proc fs
114  * \param       data            unused
115  * \retval      0               success
116  */
117 static int nodemap_ranges_show(struct seq_file *m, void *data)
118 {
119         struct lu_nodemap               *nodemap;
120         struct lu_nid_range             *range;
121         struct interval_node_extent     ext;
122         char                            start_nidstr[LNET_NIDSTR_SIZE];
123         char                            end_nidstr[LNET_NIDSTR_SIZE];
124         bool                            cont = false;
125         int rc;
126
127         mutex_lock(&active_config_lock);
128         nodemap = nodemap_lookup(m->private);
129         if (IS_ERR(nodemap)) {
130                 mutex_unlock(&active_config_lock);
131                 rc = PTR_ERR(nodemap);
132                 CERROR("cannot find nodemap '%s': rc = %d\n",
133                         (char *)m->private, rc);
134                 return rc;
135         }
136
137         seq_printf(m, "[\n");
138         down_read(&active_config->nmc_range_tree_lock);
139         list_for_each_entry(range, &nodemap->nm_ranges, rn_list) {
140                 if (cont)
141                         seq_printf(m, ",\n");
142                 cont = 1;
143                 ext = range->rn_node.in_extent;
144                 libcfs_nid2str_r(ext.start, start_nidstr, sizeof(start_nidstr));
145                 libcfs_nid2str_r(ext.end, end_nidstr, sizeof(end_nidstr));
146                 seq_printf(m, " { id: %u, start_nid: %s, end_nid: %s }",
147                            range->rn_id, start_nidstr, end_nidstr);
148         }
149         up_read(&active_config->nmc_range_tree_lock);
150         mutex_unlock(&active_config_lock);
151         seq_printf(m, "\n");
152         seq_printf(m, "]\n");
153
154         nodemap_putref(nodemap);
155         return 0;
156 }
157
158 /**
159  * Connects nodemap_idmap_show to proc file.
160  *
161  * \param       inode           inode of seq file in proc fs
162  * \param       file            seq file
163  * \retval      0               success
164  */
165 static int nodemap_ranges_open(struct inode *inode, struct file *file)
166 {
167         return single_open(file, nodemap_ranges_show, PDE_DATA(inode));
168 }
169
170 /**
171  * Reads and prints the fileset for the given nodemap.
172  *
173  * \param       m               seq file in proc fs
174  * \param       data            unused
175  * \retval      0               success
176  */
177 static int nodemap_fileset_seq_show(struct seq_file *m, void *data)
178 {
179         struct lu_nodemap *nodemap;
180         int rc = 0;
181
182         mutex_lock(&active_config_lock);
183         nodemap = nodemap_lookup(m->private);
184         mutex_unlock(&active_config_lock);
185         if (IS_ERR(nodemap)) {
186                 rc = PTR_ERR(nodemap);
187                 CERROR("cannot find nodemap '%s': rc = %d\n",
188                         (char *)m->private, rc);
189                 return rc;
190         }
191
192         seq_printf(m, "%s\n", nodemap->nm_fileset);
193         nodemap_putref(nodemap);
194         return rc;
195 }
196
197 /**
198  * Set a fileset on a nodemap.
199  *
200  * \param[in] file      proc file
201  * \param[in] buffer    string, "<fileset>"
202  * \param[in] count     \a buffer length
203  * \param[in] off       unused
204  * \retval              \a count on success
205  * \retval              negative number on error
206  */
207 static ssize_t
208 nodemap_fileset_seq_write(struct file *file,
209                                       const char __user *buffer,
210                                       size_t count, loff_t *off)
211 {
212         struct seq_file *m = file->private_data;
213         char *nm_fileset;
214         int rc = 0;
215         ENTRY;
216
217         if (count == 0)
218                 RETURN(0);
219
220         if (count > PATH_MAX)
221                 RETURN(-EINVAL);
222
223         OBD_ALLOC(nm_fileset, count);
224         if (nm_fileset == NULL)
225                 RETURN(-ENOMEM);
226
227         if (copy_from_user(nm_fileset, buffer, count))
228                 GOTO(out, rc = -EFAULT);
229
230         rc = nodemap_set_fileset(m->private, nm_fileset);
231         if (rc != 0)
232                 GOTO(out, rc = -EINVAL);
233
234         rc = count;
235 out:
236         OBD_FREE(nm_fileset, count);
237
238         return rc;
239 }
240 LPROC_SEQ_FOPS(nodemap_fileset);
241
242 /**
243  * Reads and prints the exports attached to the given nodemap.
244  *
245  * \param       m               seq file in proc fs, stores nodemap
246  * \param       data            unused
247  * \retval      0               success
248  */
249 static int nodemap_exports_show(struct seq_file *m, void *data)
250 {
251         struct lu_nodemap *nodemap;
252         struct obd_export *exp;
253         char nidstr[LNET_NIDSTR_SIZE] = "<unknown>";
254         int rc;
255
256         mutex_lock(&active_config_lock);
257         nodemap = nodemap_lookup(m->private);
258         mutex_unlock(&active_config_lock);
259         if (IS_ERR(nodemap)) {
260                 rc = PTR_ERR(nodemap);
261                 CERROR("cannot find nodemap '%s': rc = %d\n",
262                         (char *)m->private, rc);
263                 return rc;
264         }
265
266         seq_printf(m, "[\n");
267
268         mutex_lock(&nodemap->nm_member_list_lock);
269         list_for_each_entry(exp, &nodemap->nm_member_list,
270                             exp_target_data.ted_nodemap_member) {
271                 if (exp->exp_connection != NULL)
272                         libcfs_nid2str_r(exp->exp_connection->c_peer.nid,
273                                          nidstr, sizeof(nidstr));
274
275                 seq_printf(m, " { nid: %s, uuid: %s },",
276                            nidstr, exp->exp_client_uuid.uuid);
277         }
278         mutex_unlock(&nodemap->nm_member_list_lock);
279
280         seq_printf(m, "\n");
281         seq_printf(m, "]\n");
282
283         nodemap_putref(nodemap);
284         return 0;
285 }
286
287 /**
288  * Attaches nodemap_idmap_show to proc file.
289  *
290  * \param       inode           inode of seq file in proc fs
291  * \param       file            seq file
292  * \retval      0               success
293  */
294 static int nodemap_exports_open(struct inode *inode, struct file *file)
295 {
296         return single_open(file, nodemap_exports_show, PDE_DATA(inode));
297 }
298
299 /**
300  * Reads and prints the active flag for the given nodemap.
301  *
302  * \param       m               seq file in proc fs
303  * \param       data            unused
304  * \retval      0               success
305  */
306 static int nodemap_active_seq_show(struct seq_file *m, void *data)
307 {
308         seq_printf(m, "%u\n", (unsigned int)nodemap_active);
309         return 0;
310 }
311
312 /**
313  * Activate/deactivate nodemap.
314  *
315  * \param[in] file      proc file
316  * \param[in] buffer    string, "1" or "0" to activate/deactivate nodemap
317  * \param[in] count     \a buffer length
318  * \param[in] off       unused
319  * \retval              \a count on success
320  * \retval              negative number on error
321  */
322 static ssize_t
323 nodemap_active_seq_write(struct file *file, const char __user *buffer,
324                          size_t count, loff_t *off)
325 {
326         char                    active_string[NODEMAP_LPROC_FLAG_LEN + 1];
327         long unsigned int       active;
328         int                     rc;
329
330         if (count == 0)
331                 return 0;
332
333         if (count >= sizeof(active_string))
334                 return -EINVAL;
335
336         if (copy_from_user(active_string, buffer, count))
337                 return -EFAULT;
338
339         active_string[count] = '\0';
340         rc = kstrtoul(active_string, 10, &active);
341         if (rc != 0)
342                 return -EINVAL;
343
344         nodemap_activate(active);
345
346         return count;
347 }
348 LPROC_SEQ_FOPS(nodemap_active);
349
350 /**
351  * Reads and prints the nodemap ID for the given nodemap.
352  *
353  * \param       m               seq file in proc fs
354  * \param       data            unused
355  * \retval      0               success
356  */
357 static int nodemap_id_seq_show(struct seq_file *m, void *data)
358 {
359         struct lu_nodemap *nodemap;
360
361         mutex_lock(&active_config_lock);
362         nodemap = nodemap_lookup(m->private);
363         mutex_unlock(&active_config_lock);
364         if (IS_ERR(nodemap)) {
365                 int rc = PTR_ERR(nodemap);
366                 CERROR("cannot find nodemap '%s': rc = %d\n",
367                         (char *)m->private, rc);
368                 return rc;
369         }
370
371         seq_printf(m, "%u\n", nodemap->nm_id);
372         nodemap_putref(nodemap);
373         return 0;
374 }
375 LPROC_SEQ_FOPS_RO(nodemap_id);
376
377 /**
378  * Reads and prints the root squash UID for the given nodemap.
379  *
380  * \param       m               seq file in proc fs
381  * \param       data            unused
382  * \retval      0               success
383  */
384 static int nodemap_squash_uid_seq_show(struct seq_file *m, void *data)
385 {
386         struct lu_nodemap *nodemap;
387
388         mutex_lock(&active_config_lock);
389         nodemap = nodemap_lookup(m->private);
390         mutex_unlock(&active_config_lock);
391         if (IS_ERR(nodemap)) {
392                 int rc = PTR_ERR(nodemap);
393                 CERROR("cannot find nodemap '%s': rc = %d\n",
394                         (char *)m->private, rc);
395                 return rc;
396         }
397
398         seq_printf(m, "%u\n", nodemap->nm_squash_uid);
399         nodemap_putref(nodemap);
400         return 0;
401 }
402
403 /**
404  * Reads and prints the root squash GID for the given nodemap.
405  *
406  * \param       m               seq file in proc fs
407  * \param       data            unused
408  * \retval      0               success
409  */
410 static int nodemap_squash_gid_seq_show(struct seq_file *m, void *data)
411 {
412         struct lu_nodemap *nodemap;
413
414         mutex_lock(&active_config_lock);
415         nodemap = nodemap_lookup(m->private);
416         mutex_unlock(&active_config_lock);
417         if (IS_ERR(nodemap)) {
418                 int rc = PTR_ERR(nodemap);
419                 CERROR("cannot find nodemap '%s': rc = %d\n",
420                         (char *)m->private, rc);
421                 return rc;
422         }
423
424         seq_printf(m, "%u\n", nodemap->nm_squash_gid);
425         nodemap_putref(nodemap);
426         return 0;
427 }
428
429 /**
430  * Reads and prints the trusted flag for the given nodemap.
431  *
432  * \param       m               seq file in proc fs
433  * \param       data            unused
434  * \retval      0               success
435  */
436 static int nodemap_trusted_seq_show(struct seq_file *m, void *data)
437 {
438         struct lu_nodemap *nodemap;
439
440         mutex_lock(&active_config_lock);
441         nodemap = nodemap_lookup(m->private);
442         mutex_unlock(&active_config_lock);
443         if (IS_ERR(nodemap)) {
444                 int rc = PTR_ERR(nodemap);
445
446                 CERROR("cannot find nodemap '%s': rc = %d\n",
447                         (char *)m->private, rc);
448                 return rc;
449         }
450
451         seq_printf(m, "%d\n", (int)nodemap->nmf_trust_client_ids);
452         nodemap_putref(nodemap);
453         return 0;
454 }
455
456 /**
457  * Reads and prints the admin flag for the given nodemap.
458  *
459  * \param       m               seq file in proc fs
460  * \param       data            unused
461  * \retval      0               success
462  */
463 static int nodemap_admin_seq_show(struct seq_file *m, void *data)
464 {
465         struct lu_nodemap *nodemap;
466         int rc;
467
468         mutex_lock(&active_config_lock);
469         nodemap = nodemap_lookup(m->private);
470         mutex_unlock(&active_config_lock);
471         if (IS_ERR(nodemap)) {
472                 rc = PTR_ERR(nodemap);
473                 CERROR("cannot find nodemap '%s': rc = %d\n",
474                         (char *)m->private, rc);
475                 return rc;
476         }
477
478         seq_printf(m, "%d\n", (int)nodemap->nmf_allow_root_access);
479         nodemap_putref(nodemap);
480         return 0;
481 }
482
483 /**
484  * Reads and prints the mapping mode for the given nodemap.
485  *
486  * \param       m               seq file in proc fs
487  * \param       data            unused
488  * \retval      0               success
489  */
490 static int nodemap_map_mode_seq_show(struct seq_file *m, void *data)
491 {
492         struct lu_nodemap *nodemap;
493         int rc;
494
495         mutex_lock(&active_config_lock);
496         nodemap = nodemap_lookup(m->private);
497         mutex_unlock(&active_config_lock);
498         if (IS_ERR(nodemap)) {
499                 rc = PTR_ERR(nodemap);
500                 CERROR("cannot find nodemap '%s': rc = %d\n",
501                         (char *)m->private, rc);
502                 return rc;
503         }
504
505         if (nodemap->nmf_map_uid_only)
506                 seq_printf(m, "uid_only\n");
507         else if (nodemap->nmf_map_gid_only)
508                 seq_printf(m, "gid_only\n");
509         else
510                 seq_printf(m, "both\n");
511
512         nodemap_putref(nodemap);
513         return 0;
514 }
515
516 /**
517  * Reads and prints the deny_unknown flag for the given nodemap.
518  *
519  * \param       m               seq file in proc fs
520  * \param       data            unused
521  * \retval      0               success
522  */
523 static int nodemap_deny_unknown_seq_show(struct seq_file *m, void *data)
524 {
525         struct lu_nodemap *nodemap;
526         int rc;
527
528         mutex_lock(&active_config_lock);
529         nodemap = nodemap_lookup(m->private);
530         mutex_unlock(&active_config_lock);
531         if (IS_ERR(nodemap)) {
532                 rc = PTR_ERR(nodemap);
533                 CERROR("cannot find nodemap '%s': rc = %d\n",
534                         (char *)m->private, rc);
535                 return rc;
536         }
537
538         seq_printf(m, "%d\n", (int)nodemap->nmf_deny_unknown);
539         nodemap_putref(nodemap);
540         return 0;
541 }
542
543 #ifdef NODEMAP_PROC_DEBUG
544 /**
545  * Helper functions to set nodemap flags.
546  *
547  * \param[in] buffer    string, which is "1" or "0" to set/unset flag
548  * \param[in] count     \a buffer length
549  * \param[out] flag_p   where to store flag value
550  * \retval              \a count on success
551  * \retval              negative number on error
552  */
553 static int nodemap_proc_read_flag(const char __user *buffer,
554                                   unsigned long count, unsigned int *flag_p)
555 {
556         char                    scratch[NODEMAP_LPROC_FLAG_LEN + 1];
557         long unsigned int       flag_buf;
558         int                     rc;
559
560         if (count == 0)
561                 return 0;
562
563         if (count >= sizeof(scratch))
564                 return -EINVAL;
565
566         if (copy_from_user(scratch, buffer, count))
567                 return -EFAULT;
568
569         scratch[count] = '\0';
570         rc = kstrtoul(scratch, 10, &flag_buf);
571         if (rc != 0)
572                 return -EINVAL;
573
574         *flag_p = flag_buf;
575
576         return count;
577 }
578
579 /**
580  * Set the squash UID.
581  *
582  * \param[in] file      proc file
583  * \param[in] buffer    string representing squash UID to set
584  * \param[in] count     \a buffer length
585  * \param[in] off       unused
586  * \retval              \a count on success
587  * \retval              negative number on error
588  */
589 static ssize_t
590 nodemap_squash_uid_seq_write(struct file *file, const char __user *buffer,
591                              size_t count, loff_t *off)
592 {
593         char                     squash[NODEMAP_LPROC_ID_LEN + 1];
594         struct seq_file         *m = file->private_data;
595         long unsigned int        squash_uid;
596         int                      rc;
597
598         if (count == 0)
599                 return 0;
600
601         if (count >= sizeof(squash))
602                 return -EINVAL;
603
604         if (copy_from_user(squash, buffer, count))
605                 return -EFAULT;
606
607         squash[count] = '\0';
608         rc = kstrtoul(squash, 10, &squash_uid);
609         if (rc != 0)
610                 return -EINVAL;
611
612         rc = nodemap_set_squash_uid(m->private, squash_uid);
613         if (rc != 0)
614                 return rc;
615
616         return count;
617 }
618
619 /**
620  * Set the squash GID.
621  *
622  * \param[in] file      proc file
623  * \param[in] buffer    string representing squash GID to set
624  * \param[in] count     \a buffer length
625  * \param[in] off       unused
626  * \retval              \a count on success
627  * \retval              negative number on error
628  */
629 static ssize_t
630 nodemap_squash_gid_seq_write(struct file *file, const char __user *buffer,
631                              size_t count, loff_t *off)
632 {
633         char                     squash[NODEMAP_LPROC_ID_LEN + 1];
634         struct seq_file         *m = file->private_data;
635         long unsigned int        squash_gid;
636         int                      rc;
637
638         if (count == 0)
639                 return 0;
640
641         if (count >= sizeof(squash))
642                 return -EINVAL;
643
644         if (copy_from_user(squash, buffer, count))
645                 return -EFAULT;
646
647         squash[count] = '\0';
648         rc = kstrtoul(squash, 10, &squash_gid);
649         if (rc != 0)
650                 return -EINVAL;
651
652         rc = nodemap_set_squash_gid(m->private, squash_gid);
653         if (rc != 0)
654                 return rc;
655
656         return count;
657 }
658
659 /**
660  * Set/unset the trusted flag.
661  *
662  * \param[in] file      proc file
663  * \param[in] buffer    string, "1" or "0"
664  * \param[in] count     \a buffer length
665  * \param[in] off       unused
666  * \retval              \a count on success
667  * \retval              negative number on error
668  */
669 static ssize_t
670 nodemap_trusted_seq_write(struct file *file, const char __user *buffer,
671                           size_t count, loff_t *off)
672 {
673         struct seq_file         *m = file->private_data;
674         int                     flags;
675         int                     rc;
676
677         rc = nodemap_proc_read_flag(buffer, count, &flags);
678         if (rc < 0)
679                 return rc;
680
681         rc = nodemap_set_trust_client_ids(m->private, flags);
682         if (rc != 0)
683                 return rc;
684
685         return count;
686 }
687
688 /**
689  * Set/unset the admin flag.
690  *
691  * \param[in] file      proc file
692  * \param[in] buffer    string, "1" or "0"
693  * \param[in] count     \a buffer length
694  * \param[in] off       unused
695  * \retval              \a count on success
696  * \retval              negative number on error
697  */
698 static ssize_t
699 nodemap_admin_seq_write(struct file *file, const char __user *buffer,
700                         size_t count, loff_t *off)
701 {
702         struct seq_file         *m = file->private_data;
703         int                     flags;
704         int                     rc;
705
706         rc = nodemap_proc_read_flag(buffer, count, &flags);
707         if (rc < 0)
708                 return rc;
709
710         rc = nodemap_set_allow_root(m->private, flags);
711         if (rc != 0)
712                 return rc;
713
714         return count;
715 }
716
717 /**
718  * Add a nodemap.
719  *
720  * \param[in] file      proc file
721  * \param[in] buffer    string, name of the nodemap to add
722  * \param[in] count     \a buffer length
723  * \param[in] off       unused
724  * \retval              \a count on success
725  * \retval              negative number on error
726  */
727 static ssize_t
728 lprocfs_add_nodemap_seq_write(struct file *file, const char __user *buffer,
729                               size_t count, loff_t *off)
730 {
731         char    nodemap_name[LUSTRE_NODEMAP_NAME_LENGTH + 1];
732         char    *cpybuf = NULL;
733         char    *pos;
734         int     rc;
735
736         if (count == 0)
737                 return 0;
738
739         if (count >= sizeof(nodemap_name))
740                 return -EINVAL;
741
742         if (copy_from_user(nodemap_name, buffer, count))
743                 return -EFAULT;
744
745         nodemap_name[count] = '\0';
746
747         cpybuf = nodemap_name;
748         pos = strsep(&cpybuf, " \n");
749         if (pos == NULL)
750                 return -EINVAL;
751
752         rc = nodemap_add(nodemap_name);
753         if (rc == 0)
754                 rc = count;
755
756         return rc;
757 }
758 LPROC_SEQ_FOPS_WO_TYPE(nodemap, add_nodemap);
759
760 /**
761  * Delete a nodemap.
762  *
763  * \param[in] file      proc file
764  * \param[in] buffer    string, name of the nodemap to delete
765  * \param[in] count     \a buffer length
766  * \param[in] off       unused
767  * \retval              \a count on success
768  * \retval              negative number on error
769  */
770 static ssize_t
771 lprocfs_del_nodemap_seq_write(struct file *file, const char __user *buffer,
772                               size_t count, loff_t *off)
773 {
774         char    nodemap_name[LUSTRE_NODEMAP_NAME_LENGTH + 1];
775         char    *cpybuf = NULL;
776         char    *pos;
777         int     rc = count;
778
779         if (count == 0)
780                 return 0;
781
782         if (count >= sizeof(nodemap_name))
783                 return -EINVAL;
784
785         if (copy_from_user(nodemap_name, buffer, count))
786                 return -EFAULT;
787
788         nodemap_name[count] = '\0';
789
790         cpybuf = nodemap_name;
791         pos = strsep(&cpybuf, " \n");
792         if (pos == NULL)
793                 return -EINVAL;
794
795         rc = nodemap_del(nodemap_name);
796         if (rc == 0)
797                 rc = count;
798
799         return rc;
800
801 }
802 LPROC_SEQ_FOPS_WO_TYPE(nodemap, del_nodemap);
803
804 /**
805  * Helper function to parse a NID string.
806  *
807  * \param[in] rangestr  string representation of NIDs, see libcfs_str2nid()
808  * \param[out] nids     array of two nids
809  * \retval              0 on success
810  * \retval              negative number on error
811  */
812 static int parse_nids(char *rangestr, lnet_nid_t nids[2])
813 {
814         struct list_head        nidlist;
815         char                    nidstr[2][LNET_NIDSTR_SIZE];
816         char                    nidrange_str[2 * LNET_NIDSTR_SIZE + 2];
817         int                     rc = 0;
818
819         INIT_LIST_HEAD(&nidlist);
820
821         if (cfs_parse_nidlist(rangestr, strlen(rangestr),
822             &nidlist) <= 0)
823                 return -EINVAL;
824
825         if (!cfs_nidrange_is_contiguous(&nidlist))
826                 return -EINVAL;
827
828         cfs_nidrange_find_min_max(&nidlist, nidstr[0], nidstr[1],
829                                   LNET_NIDSTR_SIZE);
830         snprintf(nidrange_str, sizeof(nidrange_str), "%s:%s",
831                 nidstr[0], nidstr[1]);
832
833         rc = nodemap_parse_range(nidrange_str, nids);
834         if (rc != 0)
835                 return -EINVAL;
836
837         cfs_free_nidlist(&nidlist);
838
839         return 0;
840 }
841
842 /**
843  * Add a NID range to nodemap.
844  *
845  * \param[in] file      proc file
846  * \param[in] buffer    string, "<nodemap name> <nid range>"
847  * \param[in] count     \a buffer length
848  * \param[in] off       unused
849  * \retval              \a count on success
850  * \retval              negative number on error
851  */
852 static ssize_t
853 lprocfs_add_nodemap_range_seq_write(struct file *file,
854                                     const char __user *buffer,
855                                     size_t count, loff_t *off)
856 {
857         char                    name_range[LUSTRE_NODEMAP_NAME_LENGTH +
858                                            LNET_NIDSTR_SIZE * 2 + 2];
859         char                    *cpybuf = NULL;
860         char                    *name;
861         char                    *rangestr = NULL;
862         lnet_nid_t              nids[2];
863         int                     rc;
864
865         if (count == 0)
866                 return 0;
867
868         if (count >= sizeof(name_range))
869                 GOTO(out, rc = -EINVAL);
870
871         if (copy_from_user(name_range, buffer, count))
872                 GOTO(out, rc = -EFAULT);
873
874         name_range[count] = '\0';
875
876         cpybuf = name_range;
877         name = strsep(&cpybuf, " ");
878         if (name == NULL)
879                 GOTO(out, rc = -EINVAL);
880
881         rangestr = strsep(&cpybuf, " \n");
882         if (rangestr == NULL)
883                 GOTO(out, rc = -EINVAL);
884
885         rc = parse_nids(rangestr, nids);
886         if (rc != 0)
887                 GOTO(out, rc = rc);
888
889         rc = nodemap_add_range(name, nids);
890         if (rc != 0)
891                 GOTO(out, rc = -EINVAL);
892
893         if (rc == 0)
894                 rc = count;
895
896 out:
897         return rc;
898 }
899 LPROC_SEQ_FOPS_WO_TYPE(nodemap, add_nodemap_range);
900
901 /**
902  * Delete a NID range from nodemap.
903  *
904  * \param[in] file      proc file
905  * \param[in] buffer    string, "<nodemap name> <nid range>"
906  * \param[in] count     \a buffer length
907  * \param[in] off       unused
908  * \retval              \a count on success
909  * \retval              negative number on error
910  */
911 static ssize_t
912 lprocfs_del_nodemap_range_seq_write(struct file *file,
913                                     const char __user *buffer,
914                                     size_t count, loff_t *off)
915 {
916         char                    name_range[LUSTRE_NODEMAP_NAME_LENGTH +
917                                            LNET_NIDSTR_SIZE * 2 + 2];
918         char                    *cpybuf = NULL;
919         char                    *name;
920         char                    *rangestr = NULL;
921         lnet_nid_t              nids[2];
922         int                     rc;
923
924         if (count == 0)
925                 return 0;
926
927         if (count >= sizeof(name_range))
928                 GOTO(out, rc = -EINVAL);
929
930         if (copy_from_user(name_range, buffer, count))
931                 GOTO(out, rc = -EFAULT);
932
933         name_range[count] = '\0';
934
935         cpybuf = name_range;
936         name = strsep(&cpybuf, " ");
937         if (name == NULL)
938                 GOTO(out, rc = -EINVAL);
939
940         rangestr = strsep(&cpybuf, " \n");
941         if (rangestr == NULL)
942                 GOTO(out, rc = -EINVAL);
943
944         rc = parse_nids(rangestr, nids);
945         if (rc != 0)
946                 GOTO(out, rc = rc);
947
948         rc = nodemap_del_range(name, nids);
949         if (rc != 0)
950                 GOTO(out, rc = -EINVAL);
951
952         if (rc == 0)
953                 rc = count;
954
955 out:
956         return rc;
957 }
958 LPROC_SEQ_FOPS_WO_TYPE(nodemap, del_nodemap_range);
959
960 /**
961  * Add an idmap to nodemap.
962  *
963  * \param[in] file      proc file
964  * \param[in] buffer    string, "<nodemap name> <uid|gid> <idmap>"
965  * \param[in] count     \a buffer length
966  * \param[in] off       unused
967  * \retval              \a count on success
968  * \retval              negative number on error
969  */
970 static ssize_t
971 lprocfs_add_nodemap_idmap_seq_write(struct file *file,
972                                     const char __user *buffer,
973                                     size_t count, loff_t *off)
974 {
975         char                    name_idmapstr[LUSTRE_NODEMAP_NAME_LENGTH + 16];
976         char                    *cpybuf = NULL;
977         char                    *name;
978         char                    *idtypestr = NULL;
979         char                    *idmapstr = NULL;
980         __u32                   idmap[2];
981         int                     rc = count;
982
983         if (count == 0)
984                 return 0;
985
986         if (count >= sizeof(name_idmapstr))
987                 GOTO(out, rc = -EINVAL);
988
989         if (copy_from_user(name_idmapstr, buffer, count))
990                 GOTO(out, rc = -EFAULT);
991
992         name_idmapstr[count] = '\0';
993
994         cpybuf = name_idmapstr;
995         name = strsep(&cpybuf, " ");
996         if (name == NULL)
997                 GOTO(out, rc = -EINVAL);
998
999         idtypestr = strsep(&cpybuf, " ");
1000         if (idtypestr == NULL)
1001                 GOTO(out, rc = -EINVAL);
1002
1003         idmapstr = strsep(&cpybuf, " \n");
1004         if (idmapstr == NULL)
1005                 GOTO(out, rc = -EINVAL);
1006
1007         rc = nodemap_parse_idmap(idmapstr, idmap);
1008         if (rc != 0)
1009                 GOTO(out, rc = -EINVAL);
1010
1011         if (strcmp(idtypestr, "uid") == 0)
1012                 rc = nodemap_add_idmap(name, NODEMAP_UID, idmap);
1013         else if (strcmp(idtypestr, "gid") == 0)
1014                 rc = nodemap_add_idmap(name, NODEMAP_GID, idmap);
1015         else
1016                 GOTO(out, rc = -EINVAL);
1017
1018         if (rc != 0)
1019                 GOTO(out, rc = -EINVAL);
1020
1021         if (rc == 0)
1022                 rc = count;
1023
1024 out:
1025         return rc;
1026 }
1027 LPROC_SEQ_FOPS_WO_TYPE(nodemap, add_nodemap_idmap);
1028
1029 /**
1030  * Delete an idmap from nodemap.
1031  *
1032  * \param[in] file      proc file
1033  * \param[in] buffer    string, "<nodemap name> <uid|gid> <idmap>"
1034  * \param[in] count     \a buffer length
1035  * \param[in] off       unused
1036  * \retval              \a count on success
1037  * \retval              negative number on error
1038  */
1039 static ssize_t
1040 lprocfs_del_nodemap_idmap_seq_write(struct file *file,
1041                                     const char __user *buffer,
1042                                     size_t count, loff_t *off)
1043 {
1044         char                    name_idmapstr[LUSTRE_NODEMAP_NAME_LENGTH + 16];
1045         char                    *cpybuf = NULL;
1046         char                    *name;
1047         char                    *idtypestr = NULL;
1048         char                    *idmapstr = NULL;
1049         __u32                   idmap[2];
1050         int                     rc = count;
1051
1052         if (count == 0)
1053                 return 0;
1054
1055         if (count >= sizeof(name_idmapstr))
1056                 GOTO(out, rc = -EINVAL);
1057
1058         if (copy_from_user(name_idmapstr, buffer, count))
1059                 GOTO(out, rc = -EFAULT);
1060
1061         name_idmapstr[count] = '\0';
1062
1063         cpybuf = name_idmapstr;
1064         name = strsep(&cpybuf, " ");
1065         if (name == NULL)
1066                 GOTO(out, rc = -EINVAL);
1067
1068         idtypestr = strsep(&cpybuf, " ");
1069         if (idtypestr == NULL)
1070                 GOTO(out, rc = -EINVAL);
1071
1072         idmapstr = strsep(&cpybuf, " \n");
1073         if (idmapstr == NULL)
1074                 GOTO(out, rc = -EINVAL);
1075
1076         rc = nodemap_parse_idmap(idmapstr, idmap);
1077         if (rc != 0)
1078                 GOTO(out, rc = -EINVAL);
1079
1080         if (strcmp(idtypestr, "uid") == 0)
1081                 rc = nodemap_del_idmap(name, NODEMAP_UID, idmap);
1082         else if (strcmp(idtypestr, "gid") == 0)
1083                 rc = nodemap_del_idmap(name, NODEMAP_GID, idmap);
1084         else
1085                 GOTO(out, rc = -EINVAL);
1086
1087         if (rc != 0)
1088                 GOTO(out, rc = -EINVAL);
1089
1090         if (rc == 0)
1091                 rc = count;
1092
1093 out:
1094         return rc;
1095 }
1096 LPROC_SEQ_FOPS_WO_TYPE(nodemap, del_nodemap_idmap);
1097 #endif /* NODEMAP_PROC_DEBUG */
1098
1099 static struct lprocfs_vars lprocfs_nm_module_vars[] = {
1100         {
1101                 .name           = "active",
1102                 .fops           = &nodemap_active_fops,
1103         },
1104 #ifdef NODEMAP_PROC_DEBUG
1105         {
1106                 .name           = "add_nodemap",
1107                 .fops           = &nodemap_add_nodemap_fops,
1108         },
1109         {
1110                 .name           = "remove_nodemap",
1111                 .fops           = &nodemap_del_nodemap_fops,
1112         },
1113         {
1114                 .name           = "add_nodemap_range",
1115                 .fops           = &nodemap_add_nodemap_range_fops,
1116         },
1117         {
1118                 .name           = "del_nodemap_range",
1119                 .fops           = &nodemap_del_nodemap_range_fops,
1120         },
1121         {
1122                 .name           = "add_nodemap_idmap",
1123                 .fops           = &nodemap_add_nodemap_idmap_fops,
1124         },
1125         {
1126                 .name           = "del_nodemap_idmap",
1127                 .fops           = &nodemap_del_nodemap_idmap_fops,
1128         },
1129 #endif /* NODEMAP_PROC_DEBUG */
1130         {
1131                 NULL
1132         }
1133 };
1134
1135 #ifdef NODEMAP_PROC_DEBUG
1136 LPROC_SEQ_FOPS(nodemap_trusted);
1137 LPROC_SEQ_FOPS(nodemap_admin);
1138 LPROC_SEQ_FOPS(nodemap_squash_uid);
1139 LPROC_SEQ_FOPS(nodemap_squash_gid);
1140 #else
1141 LPROC_SEQ_FOPS_RO(nodemap_trusted);
1142 LPROC_SEQ_FOPS_RO(nodemap_admin);
1143 LPROC_SEQ_FOPS_RO(nodemap_squash_uid);
1144 LPROC_SEQ_FOPS_RO(nodemap_squash_gid);
1145 #endif
1146
1147 LPROC_SEQ_FOPS_RO(nodemap_deny_unknown);
1148 LPROC_SEQ_FOPS_RO(nodemap_map_mode);
1149
1150 const struct file_operations nodemap_ranges_fops = {
1151         .open                   = nodemap_ranges_open,
1152         .read                   = seq_read,
1153         .llseek                 = seq_lseek,
1154         .release                = single_release
1155 };
1156
1157 const struct file_operations nodemap_idmap_fops = {
1158         .open                   = nodemap_idmap_open,
1159         .read                   = seq_read,
1160         .llseek                 = seq_lseek,
1161         .release                = single_release
1162 };
1163
1164 const struct file_operations nodemap_exports_fops = {
1165         .open                   = nodemap_exports_open,
1166         .read                   = seq_read,
1167         .llseek                 = seq_lseek,
1168         .release                = single_release
1169 };
1170
1171 static struct lprocfs_vars lprocfs_nodemap_vars[] = {
1172         {
1173                 .name           = "id",
1174                 .fops           = &nodemap_id_fops,
1175         },
1176         {
1177                 .name           = "trusted_nodemap",
1178                 .fops           = &nodemap_trusted_fops,
1179         },
1180         {
1181                 .name           = "admin_nodemap",
1182                 .fops           = &nodemap_admin_fops,
1183         },
1184         {
1185                 .name           = "deny_unknown",
1186                 .fops           = &nodemap_deny_unknown_fops,
1187         },
1188         {
1189                 .name           = "map_mode",
1190                 .fops           = &nodemap_map_mode_fops,
1191         },
1192         {
1193                 .name           = "squash_uid",
1194                 .fops           = &nodemap_squash_uid_fops,
1195         },
1196         {
1197                 .name           = "squash_gid",
1198                 .fops           = &nodemap_squash_gid_fops,
1199         },
1200         {
1201                 .name           = "ranges",
1202                 .fops           = &nodemap_ranges_fops,
1203         },
1204         {
1205                 .name           = "fileset",
1206                 .fops           = &nodemap_fileset_fops,
1207         },
1208         {
1209                 .name           = "exports",
1210                 .fops           = &nodemap_exports_fops,
1211         },
1212         {
1213                 .name           = "idmap",
1214                 .fops           = &nodemap_idmap_fops,
1215         },
1216         {
1217                 NULL
1218         }
1219 };
1220
1221 static struct lprocfs_vars lprocfs_default_nodemap_vars[] = {
1222         {
1223                 .name           = "id",
1224                 .fops           = &nodemap_id_fops,
1225         },
1226         {
1227                 .name           = "trusted_nodemap",
1228                 .fops           = &nodemap_trusted_fops,
1229         },
1230         {
1231                 .name           = "admin_nodemap",
1232                 .fops           = &nodemap_admin_fops,
1233         },
1234         {
1235                 .name           = "squash_uid",
1236                 .fops           = &nodemap_squash_uid_fops,
1237         },
1238         {
1239                 .name           = "squash_gid",
1240                 .fops           = &nodemap_squash_gid_fops,
1241         },
1242         {
1243                 .name           = "exports",
1244                 .fops           = &nodemap_exports_fops,
1245         },
1246         {
1247                 NULL
1248         }
1249 };
1250
1251 /**
1252  * Initialize the nodemap procfs directory.
1253  *
1254  * \retval      0               success
1255  */
1256 int nodemap_procfs_init(void)
1257 {
1258         int rc = 0;
1259
1260         proc_lustre_nodemap_root = lprocfs_register(LUSTRE_NODEMAP_NAME,
1261                                                     proc_lustre_root,
1262                                                     lprocfs_nm_module_vars,
1263                                                     NULL);
1264         if (IS_ERR(proc_lustre_nodemap_root)) {
1265                 rc = PTR_ERR(proc_lustre_nodemap_root);
1266                 CERROR("cannot create 'nodemap' directory: rc = %d\n",
1267                        rc);
1268                 proc_lustre_nodemap_root = NULL;
1269         }
1270         return rc;
1271 }
1272
1273 /**
1274  * Cleanup nodemap proc entry data structures.
1275  */
1276 void nodemap_procfs_exit(void)
1277 {
1278         struct nodemap_pde *nm_pde;
1279         struct nodemap_pde *tmp;
1280
1281         lprocfs_remove(&proc_lustre_nodemap_root);
1282         list_for_each_entry_safe(nm_pde, tmp, &nodemap_pde_list,
1283                                  npe_list_member) {
1284                 list_del(&nm_pde->npe_list_member);
1285                 OBD_FREE_PTR(nm_pde);
1286         }
1287 }
1288
1289 /**
1290  * Remove a nodemap's procfs entry and related data.
1291  */
1292 void lprocfs_nodemap_remove(struct nodemap_pde *nm_pde)
1293 {
1294         lprocfs_remove(&nm_pde->npe_proc_entry);
1295         list_del(&nm_pde->npe_list_member);
1296         OBD_FREE_PTR(nm_pde);
1297 }
1298
1299 /**
1300  * Register the proc directory for a nodemap
1301  *
1302  * \param       nodemap         nodemap to make the proc dir for
1303  * \param       is_default:     1 if default nodemap
1304  * \retval      0               success
1305  */
1306 int lprocfs_nodemap_register(struct lu_nodemap *nodemap, bool is_default)
1307 {
1308         struct nodemap_pde      *nm_entry;
1309         int                      rc = 0;
1310
1311         OBD_ALLOC_PTR(nm_entry);
1312         if (nm_entry == NULL)
1313                 GOTO(out, rc = -ENOMEM);
1314
1315         nm_entry->npe_proc_entry = proc_mkdir(nodemap->nm_name,
1316                                               proc_lustre_nodemap_root);
1317         if (IS_ERR(nm_entry->npe_proc_entry))
1318                 GOTO(out, rc = PTR_ERR(nm_entry->npe_proc_entry));
1319
1320         snprintf(nm_entry->npe_name, sizeof(nm_entry->npe_name), "%s",
1321                  nodemap->nm_name);
1322
1323         /* Use the nodemap name as stored on the PDE as the private data. This
1324          * is so a nodemap struct can be replaced without updating the proc
1325          * entries.
1326          */
1327         rc = lprocfs_add_vars(nm_entry->npe_proc_entry,
1328                               (is_default ? lprocfs_default_nodemap_vars :
1329                                             lprocfs_nodemap_vars),
1330                               nm_entry->npe_name);
1331         if (rc != 0)
1332                 lprocfs_remove(&nm_entry->npe_proc_entry);
1333         else
1334                 list_add(&nm_entry->npe_list_member, &nodemap_pde_list);
1335
1336 out:
1337         if (rc != 0) {
1338                 CERROR("cannot create 'nodemap/%s': rc = %d\n",
1339                        nodemap->nm_name, rc);
1340                 if (nm_entry != NULL) {
1341                         OBD_FREE_PTR(nm_entry);
1342                         nm_entry = NULL;
1343                 }
1344         }
1345
1346         nodemap->nm_pde_data = nm_entry;
1347
1348         return rc;
1349 }