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