Whamcloud - gitweb
LU-4563 Fix unsafe userspace access in many proc files
[fs/lustre-release.git] / lustre / mdt / mdt_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.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2013, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/mdt/mdt_lproc.c
37  *
38  * Author: Lai Siyao <lsy@clusterfs.com>
39  * Author: Fan Yong <fanyong@clusterfs.com>
40  */
41
42 #define DEBUG_SUBSYSTEM S_MDS
43
44 #include <linux/version.h>
45 #include <asm/statfs.h>
46
47 #include <linux/module.h>
48
49 /* LUSTRE_VERSION_CODE */
50 #include <lustre_ver.h>
51 /*
52  * struct OBD_{ALLOC,FREE}*()
53  * MDT_FAIL_CHECK
54  */
55 #include <obd_support.h>
56 /* struct obd_export */
57 #include <lustre_export.h>
58 /* struct obd_device */
59 #include <obd.h>
60 #include <obd_class.h>
61 #include <lustre_mds.h>
62 #include <lprocfs_status.h>
63 #include "mdt_internal.h"
64 #include <lnet/lib-lnet.h>
65
66 /**
67  * The rename stats output would be YAML formats, like
68  * rename_stats:
69  * - snapshot_time: 1234567890.123456
70  * - same_dir:
71  *     4kB: { samples: 1230, pct: 33, cum_pct: 45 }
72  *     8kB: { samples: 1242, pct: 33, cum_pct: 78 }
73  *     16kB: { samples: 132, pct: 3, cum_pct: 81 }
74  * - crossdir_src:
75  *     4kB: { samples: 123, pct: 33, cum_pct: 45 }
76  *     8kB: { samples: 124, pct: 33, cum_pct: 78 }
77  *     16kB: { samples: 12, pct: 3, cum_pct: 81 }
78  * - crossdir_tgt:
79  *     4kB: { samples: 123, pct: 33, cum_pct: 45 }
80  *     8kB: { samples: 124, pct: 33, cum_pct: 78 }
81  *     16kB: { samples: 12, pct: 3, cum_pct: 81 }
82  **/
83
84 #define pct(a, b) (b ? a * 100 / b : 0)
85
86 static void display_rename_stats(struct seq_file *seq, char *name,
87                                  struct obd_histogram *hist)
88 {
89         unsigned long tot, t, cum = 0;
90         int i;
91
92         tot = lprocfs_oh_sum(hist);
93         if (tot > 0)
94                 seq_printf(seq, "- %-15s\n", name);
95         /* dir size start from 4K, start i from 10(2^10) here */
96         for (i = 0; i < OBD_HIST_MAX; i++) {
97                 t = hist->oh_buckets[i];
98                 cum += t;
99                 if (cum == 0)
100                         continue;
101
102                 if (i < 10)
103                         seq_printf(seq, "%6s%d%s", " ", 1<< i, "bytes:");
104                 else if (i < 20)
105                         seq_printf(seq, "%6s%d%s", " ", 1<<(i-10), "KB:");
106                 else
107                         seq_printf(seq, "%6s%d%s", " ", 1<<(i-20), "MB:");
108
109                 seq_printf(seq, " { sample: %3lu, pct: %3lu, cum_pct: %3lu }\n",
110                            t, pct(t, tot), pct(cum, tot));
111
112                 if (cum == tot)
113                         break;
114         }
115 }
116
117 static void rename_stats_show(struct seq_file *seq,
118                               struct rename_stats *rename_stats)
119 {
120         struct timeval now;
121
122         /* this sampling races with updates */
123         do_gettimeofday(&now);
124         seq_printf(seq, "rename_stats:\n");
125         seq_printf(seq, "- %-15s %lu.%lu\n", "snapshot_time:",
126                    now.tv_sec, now.tv_usec);
127
128         display_rename_stats(seq, "same_dir",
129                              &rename_stats->hist[RENAME_SAMEDIR_SIZE]);
130         display_rename_stats(seq, "crossdir_src",
131                              &rename_stats->hist[RENAME_CROSSDIR_SRC_SIZE]);
132         display_rename_stats(seq, "crossdir_tgt",
133                              &rename_stats->hist[RENAME_CROSSDIR_TGT_SIZE]);
134 }
135
136 #undef pct
137
138 static int mdt_rename_stats_seq_show(struct seq_file *seq, void *v)
139 {
140         struct mdt_device *mdt = seq->private;
141
142         rename_stats_show(seq, &mdt->mdt_rename_stats);
143
144         return 0;
145 }
146
147 static ssize_t mdt_rename_stats_seq_write(struct file *file, const char *buf,
148                                           size_t len, loff_t *off)
149 {
150         struct seq_file *seq = file->private_data;
151         struct mdt_device *mdt = seq->private;
152         int i;
153
154         for (i = 0; i < RENAME_LAST; i++)
155                 lprocfs_oh_clear(&mdt->mdt_rename_stats.hist[i]);
156
157         return len;
158 }
159
160 LPROC_SEQ_FOPS(mdt_rename_stats);
161
162 static int lproc_mdt_attach_rename_seqstat(struct mdt_device *mdt)
163 {
164         int i;
165
166         for (i = 0; i < RENAME_LAST; i++)
167                 spin_lock_init(&mdt->mdt_rename_stats.hist[i].oh_lock);
168
169         return lprocfs_obd_seq_create(mdt2obd_dev(mdt), "rename_stats", 0644,
170                                       &mdt_rename_stats_fops, mdt);
171 }
172
173 void mdt_rename_counter_tally(struct mdt_thread_info *info,
174                               struct mdt_device *mdt,
175                               struct ptlrpc_request *req,
176                               struct mdt_object *src,
177                               struct mdt_object *tgt)
178 {
179         struct md_attr *ma = &info->mti_attr;
180         struct rename_stats *rstats = &mdt->mdt_rename_stats;
181         int rc;
182
183         ma->ma_need = MA_INODE;
184         ma->ma_valid = 0;
185         rc = mo_attr_get(info->mti_env, mdt_object_child(src), ma);
186         if (rc) {
187                 CERROR("%s: "DFID" attr_get, rc = %d\n",
188                        mdt_obd_name(mdt), PFID(mdt_object_fid(src)), rc);
189                 return;
190         }
191
192         if (src == tgt) {
193                 mdt_counter_incr(req, LPROC_MDT_SAMEDIR_RENAME);
194                 lprocfs_oh_tally_log2(&rstats->hist[RENAME_SAMEDIR_SIZE],
195                                       (unsigned int)ma->ma_attr.la_size);
196                 return;
197         }
198
199         mdt_counter_incr(req, LPROC_MDT_CROSSDIR_RENAME);
200         lprocfs_oh_tally_log2(&rstats->hist[RENAME_CROSSDIR_SRC_SIZE],
201                               (unsigned int)ma->ma_attr.la_size);
202
203         ma->ma_need = MA_INODE;
204         ma->ma_valid = 0;
205         rc = mo_attr_get(info->mti_env, mdt_object_child(tgt), ma);
206         if (rc) {
207                 CERROR("%s: "DFID" attr_get, rc = %d\n",
208                        mdt_obd_name(mdt), PFID(mdt_object_fid(tgt)), rc);
209                 return;
210         }
211
212         lprocfs_oh_tally_log2(&rstats->hist[RENAME_CROSSDIR_TGT_SIZE],
213                               (unsigned int)ma->ma_attr.la_size);
214 }
215
216 int mdt_procfs_init(struct mdt_device *mdt, const char *name)
217 {
218         struct obd_device               *obd = mdt2obd_dev(mdt);
219         struct lprocfs_static_vars       lvars;
220         int                              rc;
221         ENTRY;
222
223         LASSERT(name != NULL);
224
225         lprocfs_mdt_init_vars(&lvars);
226         rc = lprocfs_obd_setup(obd, lvars.obd_vars);
227         if (rc) {
228                 CERROR("%s: cannot create proc entries: rc = %d\n",
229                        mdt_obd_name(mdt), rc);
230                 return rc;
231         }
232
233         rc = hsm_cdt_procfs_init(mdt);
234         if (rc) {
235                 CERROR("%s: cannot create hsm proc entries: rc = %d\n",
236                        mdt_obd_name(mdt), rc);
237                 return rc;
238         }
239
240         obd->obd_proc_exports_entry = proc_mkdir("exports",
241                                                  obd->obd_proc_entry);
242         if (obd->obd_proc_exports_entry)
243                 lprocfs_add_simple(obd->obd_proc_exports_entry,
244                                    "clear", lprocfs_nid_stats_clear_read,
245                                    lprocfs_nid_stats_clear_write, obd, NULL);
246         rc = lprocfs_alloc_md_stats(obd, LPROC_MDT_LAST);
247         if (rc)
248                 return rc;
249         mdt_stats_counter_init(obd->obd_md_stats);
250
251         rc = lprocfs_job_stats_init(obd, LPROC_MDT_LAST,
252                                     mdt_stats_counter_init);
253
254         rc = lproc_mdt_attach_rename_seqstat(mdt);
255         if (rc)
256                 CERROR("%s: MDT can not create rename stats rc = %d\n",
257                        mdt_obd_name(mdt), rc);
258
259         RETURN(rc);
260 }
261
262 void mdt_procfs_fini(struct mdt_device *mdt)
263 {
264         struct obd_device *obd = mdt2obd_dev(mdt);
265
266         if (obd->obd_proc_exports_entry != NULL) {
267                 lprocfs_remove_proc_entry("clear", obd->obd_proc_exports_entry);
268                 obd->obd_proc_exports_entry = NULL;
269         }
270
271         lprocfs_free_per_client_stats(obd);
272         hsm_cdt_procfs_fini(mdt);
273         lprocfs_obd_cleanup(obd);
274         lprocfs_free_md_stats(obd);
275         lprocfs_free_obd_stats(obd);
276         lprocfs_job_stats_fini(obd);
277 }
278
279 static int lprocfs_rd_identity_expire(char *page, char **start, off_t off,
280                                       int count, int *eof, void *data)
281 {
282         struct obd_device *obd = data;
283         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
284
285         *eof = 1;
286         return snprintf(page, count, "%u\n",
287                         mdt->mdt_identity_cache->uc_entry_expire);
288 }
289
290 static int lprocfs_wr_identity_expire(struct file *file,
291                                       const char __user *buffer,
292                                       unsigned long count, void *data)
293 {
294         struct obd_device *obd = data;
295         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
296         int rc, val;
297
298         rc = lprocfs_write_helper(buffer, count, &val);
299         if (rc)
300                 return rc;
301
302         mdt->mdt_identity_cache->uc_entry_expire = val;
303         return count;
304 }
305
306 static int lprocfs_rd_identity_acquire_expire(char *page, char **start,
307                                               off_t off, int count, int *eof,
308                                               void *data)
309 {
310         struct obd_device *obd = data;
311         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
312
313         *eof = 1;
314         return snprintf(page, count, "%u\n",
315                         mdt->mdt_identity_cache->uc_acquire_expire);
316 }
317
318 static int lprocfs_wr_identity_acquire_expire(struct file *file,
319                                               const char __user *buffer,
320                                               unsigned long count,
321                                               void *data)
322 {
323         struct obd_device *obd = data;
324         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
325         int rc, val;
326
327         rc = lprocfs_write_helper(buffer, count, &val);
328         if (rc)
329                 return rc;
330
331         mdt->mdt_identity_cache->uc_acquire_expire = val;
332         return count;
333 }
334
335 static int lprocfs_rd_identity_upcall(char *page, char **start, off_t off,
336                                       int count, int *eof, void *data)
337 {
338         struct obd_device *obd = data;
339         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
340         struct upcall_cache *hash = mdt->mdt_identity_cache;
341         int len;
342
343         *eof = 1;
344         read_lock(&hash->uc_upcall_rwlock);
345         len = snprintf(page, count, "%s\n", hash->uc_upcall);
346         read_unlock(&hash->uc_upcall_rwlock);
347         return len;
348 }
349
350 static int lprocfs_wr_identity_upcall(struct file *file,
351                                       const char __user *buffer,
352                                       unsigned long count, void *data)
353 {
354         struct obd_device       *obd = data;
355         struct mdt_device       *mdt = mdt_dev(obd->obd_lu_dev);
356         struct upcall_cache     *hash = mdt->mdt_identity_cache;
357         int                      rc;
358         char                    *kernbuf;
359
360         if (count >= UC_CACHE_UPCALL_MAXPATH) {
361                 CERROR("%s: identity upcall too long\n", mdt_obd_name(mdt));
362                 return -EINVAL;
363         }
364         OBD_ALLOC(kernbuf, count + 1);
365         if (kernbuf == NULL)
366                 GOTO(failed, rc = -ENOMEM);
367         if (copy_from_user(kernbuf, buffer, count))
368                 GOTO(failed, rc = -EFAULT);
369
370         /* Remove any extraneous bits from the upcall (e.g. linefeeds) */
371         write_lock(&hash->uc_upcall_rwlock);
372         sscanf(kernbuf, "%s", hash->uc_upcall);
373         write_unlock(&hash->uc_upcall_rwlock);
374
375         if (strcmp(hash->uc_name, mdt_obd_name(mdt)) != 0)
376                 CWARN("%s: write to upcall name %s\n",
377                       mdt_obd_name(mdt), hash->uc_upcall);
378
379         if (strcmp(hash->uc_upcall, "NONE") == 0 && mdt->mdt_opts.mo_acl)
380                 CWARN("%s: disable \"identity_upcall\" with ACL enabled maybe "
381                       "cause unexpected \"EACCESS\"\n", mdt_obd_name(mdt));
382
383         CDEBUG(D_CONFIG, "%s: identity upcall set to %s\n", mdt_obd_name(mdt),
384                hash->uc_upcall);
385         OBD_FREE(kernbuf, count + 1);
386         RETURN(count);
387
388  failed:
389         if (kernbuf)
390                 OBD_FREE(kernbuf, count + 1);
391         RETURN(rc);
392 }
393
394 static int lprocfs_wr_identity_flush(struct file *file,
395                                      const char __user *buffer,
396                                      unsigned long count, void *data)
397 {
398         struct obd_device *obd = data;
399         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
400         int rc, uid;
401
402         rc = lprocfs_write_helper(buffer, count, &uid);
403         if (rc)
404                 return rc;
405
406         mdt_flush_identity(mdt->mdt_identity_cache, uid);
407         return count;
408 }
409
410 static int lprocfs_wr_identity_info(struct file *file,
411                                     const char __user *buffer,
412                                     unsigned long count, void *data)
413 {
414         struct obd_device *obd = data;
415         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
416         struct identity_downcall_data *param;
417         int size = sizeof(*param), rc, checked = 0;
418
419 again:
420         if (count < size) {
421                 CERROR("%s: invalid data count = %lu, size = %d\n",
422                        mdt_obd_name(mdt), count, size);
423                 return -EINVAL;
424         }
425
426         OBD_ALLOC(param, size);
427         if (param == NULL)
428                 return -ENOMEM;
429
430         if (copy_from_user(param, buffer, size)) {
431                 CERROR("%s: bad identity data\n", mdt_obd_name(mdt));
432                 GOTO(out, rc = -EFAULT);
433         }
434
435         if (checked == 0) {
436                 checked = 1;
437                 if (param->idd_magic != IDENTITY_DOWNCALL_MAGIC) {
438                         CERROR("%s: MDS identity downcall bad params\n",
439                                mdt_obd_name(mdt));
440                         GOTO(out, rc = -EINVAL);
441                 }
442
443                 if (param->idd_nperms > N_PERMS_MAX) {
444                         CERROR("%s: perm count %d more than maximum %d\n",
445                                mdt_obd_name(mdt), param->idd_nperms,
446                                N_PERMS_MAX);
447                         GOTO(out, rc = -EINVAL);
448                 }
449
450                 if (param->idd_ngroups > NGROUPS_MAX) {
451                         CERROR("%s: group count %d more than maximum %d\n",
452                                mdt_obd_name(mdt), param->idd_ngroups,
453                                NGROUPS_MAX);
454                         GOTO(out, rc = -EINVAL);
455                 }
456
457                 if (param->idd_ngroups) {
458                         rc = param->idd_ngroups; /* save idd_ngroups */
459                         OBD_FREE(param, size);
460                         size = offsetof(struct identity_downcall_data,
461                                         idd_groups[rc]);
462                         goto again;
463                 }
464         }
465
466         rc = upcall_cache_downcall(mdt->mdt_identity_cache, param->idd_err,
467                                    param->idd_uid, param);
468
469 out:
470         if (param != NULL)
471                 OBD_FREE(param, size);
472
473         return rc ? rc : count;
474 }
475
476 /* for debug only */
477 static int lprocfs_rd_capa(char *page, char **start, off_t off,
478                            int count, int *eof, void *data)
479 {
480         struct obd_device *obd = data;
481         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
482
483         return snprintf(page, count, "capability on: %s %s\n",
484                         mdt->mdt_lut.lut_oss_capa ? "oss" : "",
485                         mdt->mdt_lut.lut_mds_capa ? "mds" : "");
486 }
487
488 static int lprocfs_wr_capa(struct file *file, const char __user *buffer,
489                            unsigned long count, void *data)
490 {
491         struct obd_device *obd = data;
492         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
493         int val, rc;
494
495         rc = lprocfs_write_helper(buffer, count, &val);
496         if (rc)
497                 return rc;
498
499         if (val < 0 || val > 3) {
500                 CERROR("invalid capability mode, only 0/2/3 is accepted.\n"
501                        " 0:  disable fid capability\n"
502                        " 2:  enable MDS fid capability\n"
503                        " 3:  enable both MDS and OSS fid capability\n");
504                 return -EINVAL;
505         }
506
507         /* OSS fid capability needs enable both MDS and OSS fid capability on
508          * MDS */
509         if (val == 1) {
510                 CERROR("can't enable OSS fid capability only, you should use "
511                        "'3' to enable both MDS and OSS fid capability.\n");
512                 return -EINVAL;
513         }
514
515         spin_lock(&mdt->mdt_lut.lut_flags_lock);
516         mdt->mdt_lut.lut_oss_capa = !!(val & 0x1);
517         mdt->mdt_lut.lut_mds_capa = !!(val & 0x2);
518         spin_unlock(&mdt->mdt_lut.lut_flags_lock);
519         mdt->mdt_capa_conf = 1;
520         LCONSOLE_INFO("MDS %s %s MDS fid capability.\n",
521                       mdt_obd_name(mdt),
522                       mdt->mdt_lut.lut_mds_capa ? "enabled" : "disabled");
523         LCONSOLE_INFO("MDS %s %s OSS fid capability.\n",
524                       mdt_obd_name(mdt),
525                       mdt->mdt_lut.lut_oss_capa ? "enabled" : "disabled");
526         return count;
527 }
528
529 static int lprocfs_rd_capa_count(char *page, char **start, off_t off,
530                                  int count, int *eof, void *data)
531 {
532         return snprintf(page, count, "%d %d\n",
533                         capa_count[CAPA_SITE_CLIENT],
534                         capa_count[CAPA_SITE_SERVER]);
535 }
536
537 static int lprocfs_rd_site_stats(char *page, char **start, off_t off,
538                                  int count, int *eof, void *data)
539 {
540         struct obd_device *obd = data;
541         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
542
543         return lu_site_stats_print(mdt_lu_site(mdt), page, count);
544 }
545
546 static int lprocfs_rd_capa_timeout(char *page, char **start, off_t off,
547                                    int count, int *eof, void *data)
548 {
549         struct obd_device *obd = data;
550         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
551
552         return snprintf(page, count, "%lu\n", mdt->mdt_capa_timeout);
553 }
554
555 static int lprocfs_wr_capa_timeout(struct file *file, const char __user *buffer,
556                                    unsigned long count, void *data)
557 {
558         struct obd_device *obd = data;
559         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
560         int val, rc;
561
562         rc = lprocfs_write_helper(buffer, count, &val);
563         if (rc)
564                 return rc;
565
566         mdt->mdt_capa_timeout = (unsigned long)val;
567         mdt->mdt_capa_conf = 1;
568         return count;
569 }
570
571 static int lprocfs_rd_ck_timeout(char *page, char **start, off_t off, int count,
572                                  int *eof, void *data)
573 {
574         struct obd_device *obd = data;
575         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
576
577         return snprintf(page, count, "%lu\n", mdt->mdt_ck_timeout);
578 }
579
580 static int lprocfs_wr_ck_timeout(struct file *file, const char __user *buffer,
581                                  unsigned long count, void *data)
582 {
583         struct obd_device *obd = data;
584         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
585         int val, rc;
586
587         rc = lprocfs_write_helper(buffer, count, &val);
588         if (rc)
589                 return rc;
590
591         mdt->mdt_ck_timeout = (unsigned long)val;
592         mdt->mdt_capa_conf = 1;
593         return count;
594 }
595
596 #define BUFLEN (UUID_MAX + 4)
597
598 static int lprocfs_mdt_wr_evict_client(struct file *file,
599                                        const char __user *buffer,
600                                        unsigned long count, void *data)
601 {
602         char *kbuf;
603         char *tmpbuf;
604
605         OBD_ALLOC(kbuf, BUFLEN);
606         if (kbuf == NULL)
607                 return -ENOMEM;
608
609         /*
610          * OBD_ALLOC() will zero kbuf, but we only copy BUFLEN - 1
611          * bytes into kbuf, to ensure that the string is NUL-terminated.
612          * UUID_MAX should include a trailing NUL already.
613          */
614         if (copy_from_user(kbuf, buffer,
615                            min_t(unsigned long, BUFLEN - 1, count))) {
616                 count = -EFAULT;
617                 goto out;
618         }
619         tmpbuf = cfs_firststr(kbuf, min_t(unsigned long, BUFLEN - 1, count));
620
621         if (strncmp(tmpbuf, "nid:", 4) != 0) {
622                 count = lprocfs_wr_evict_client(file, buffer, count, data);
623                 goto out;
624         }
625
626         CERROR("NOT implement evict client by nid %s\n", tmpbuf);
627
628 out:
629         OBD_FREE(kbuf, BUFLEN);
630         return count;
631 }
632
633 #undef BUFLEN
634
635 static int lprocfs_rd_sec_level(char *page, char **start, off_t off,
636                                 int count, int *eof, void *data)
637 {
638         struct obd_device *obd = data;
639         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
640
641         return snprintf(page, count, "%d\n", mdt->mdt_lut.lut_sec_level);
642 }
643
644 static int lprocfs_wr_sec_level(struct file *file, const char __user *buffer,
645                                 unsigned long count, void *data)
646 {
647         struct obd_device *obd = data;
648         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
649         int val, rc;
650
651         rc = lprocfs_write_helper(buffer, count, &val);
652         if (rc)
653                 return rc;
654
655         if (val > LUSTRE_SEC_ALL || val < LUSTRE_SEC_NONE)
656                 return -EINVAL;
657
658         if (val == LUSTRE_SEC_SPECIFY) {
659                 CWARN("security level %d will be supported in future.\n",
660                       LUSTRE_SEC_SPECIFY);
661                 return -EINVAL;
662         }
663
664         mdt->mdt_lut.lut_sec_level = val;
665         return count;
666 }
667
668 static int lprocfs_rd_cos(char *page, char **start, off_t off,
669                               int count, int *eof, void *data)
670 {
671         struct obd_device *obd = data;
672         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
673
674         return snprintf(page, count, "%u\n", mdt_cos_is_enabled(mdt));
675 }
676
677 static int lprocfs_wr_cos(struct file *file, const char __user *buffer,
678                           unsigned long count, void *data)
679 {
680         struct obd_device *obd = data;
681         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
682         int val, rc;
683
684         rc = lprocfs_write_helper(buffer, count, &val);
685         if (rc)
686                 return rc;
687         mdt_enable_cos(mdt, val);
688         return count;
689 }
690
691 static int lprocfs_rd_root_squash(char *page, char **start, off_t off,
692                                   int count, int *eof, void *data)
693 {
694         struct obd_device *obd = data;
695         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
696
697         return snprintf(page, count, "%u:%u\n", mdt->mdt_squash_uid,
698                         mdt->mdt_squash_gid);
699 }
700
701 static int safe_strtoul(const char *str, char **endp, unsigned long *res)
702 {
703         char n[24];
704
705         *res = simple_strtoul(str, endp, 0);
706         if (str == *endp)
707                 return 1;
708
709         sprintf(n, "%lu", *res);
710         if (strncmp(n, str, *endp - str))
711                 /* overflow */
712                 return 1;
713         return 0;
714 }
715
716 static int lprocfs_wr_root_squash(struct file *file, const char __user *buffer,
717                                   unsigned long count, void *data)
718 {
719         struct obd_device *obd = data;
720         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
721         int rc;
722         char kernbuf[64], *tmp, *end, *errmsg;
723         unsigned long uid, gid;
724         int nouid, nogid;
725         ENTRY;
726
727         if (count >= sizeof(kernbuf)) {
728                 errmsg = "string too long";
729                 GOTO(failed_noprint, rc = -EINVAL);
730         }
731         if (copy_from_user(kernbuf, buffer, count)) {
732                 errmsg = "bad address";
733                 GOTO(failed_noprint, rc = -EFAULT);
734         }
735         kernbuf[count] = '\0';
736
737         nouid = nogid = 0;
738         if (safe_strtoul(kernbuf, &tmp, &uid)) {
739                 uid = mdt->mdt_squash_uid;
740                 nouid = 1;
741         }
742
743         /* skip ':' */
744         if (*tmp == ':') {
745                 tmp++;
746                 if (safe_strtoul(tmp, &end, &gid)) {
747                         gid = mdt->mdt_squash_gid;
748                         nogid = 1;
749                 }
750         } else {
751                 gid = mdt->mdt_squash_gid;
752                 nogid = 1;
753         }
754
755         mdt->mdt_squash_uid = uid;
756         mdt->mdt_squash_gid = gid;
757
758         if (nouid && nogid) {
759                 errmsg = "needs uid:gid format";
760                 GOTO(failed, rc = -EINVAL);
761         }
762
763         LCONSOLE_INFO("%s: root_squash is set to %u:%u\n",
764                       mdt_obd_name(mdt),
765                       mdt->mdt_squash_uid,  mdt->mdt_squash_gid);
766         RETURN(count);
767
768 failed:
769         CWARN("%s: failed to set root_squash to \"%s\", %s: rc %d\n",
770               mdt_obd_name(mdt), kernbuf, errmsg, rc);
771         RETURN(rc);
772 failed_noprint:
773         CWARN("%s: failed to set root_squash due to %s: rc %d\n",
774               mdt_obd_name(mdt), errmsg, rc);
775         RETURN(rc);
776 }
777
778 static int lprocfs_rd_nosquash_nids(char *page, char **start, off_t off,
779                                     int count, int *eof, void *data)
780 {
781         struct obd_device *obd = data;
782         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
783
784         if (mdt->mdt_nosquash_str)
785                 return snprintf(page, count, "%s\n", mdt->mdt_nosquash_str);
786         return snprintf(page, count, "NONE\n");
787 }
788
789 static int lprocfs_wr_nosquash_nids(struct file *file,
790                                     const char __user *buffer,
791                                     unsigned long count, void *data)
792 {
793         struct obd_device *obd = data;
794         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
795         int rc;
796         char *kernbuf, *errmsg;
797         cfs_list_t tmp;
798         ENTRY;
799
800         OBD_ALLOC(kernbuf, count + 1);
801         if (kernbuf == NULL) {
802                 errmsg = "no memory";
803                 GOTO(failed, rc = -ENOMEM);
804         }
805         if (copy_from_user(kernbuf, buffer, count)) {
806                 errmsg = "bad address";
807                 GOTO(failed, rc = -EFAULT);
808         }
809         kernbuf[count] = '\0';
810
811         if (!strcmp(kernbuf, "NONE") || !strcmp(kernbuf, "clear")) {
812                 /* empty string is special case */
813                 down_write(&mdt->mdt_squash_sem);
814                 if (!cfs_list_empty(&mdt->mdt_nosquash_nids)) {
815                         cfs_free_nidlist(&mdt->mdt_nosquash_nids);
816                         OBD_FREE(mdt->mdt_nosquash_str,
817                                  mdt->mdt_nosquash_strlen);
818                         mdt->mdt_nosquash_str = NULL;
819                         mdt->mdt_nosquash_strlen = 0;
820                 }
821                 up_write(&mdt->mdt_squash_sem);
822                 LCONSOLE_INFO("%s: nosquash_nids is cleared\n",
823                               mdt_obd_name(mdt));
824                 OBD_FREE(kernbuf, count + 1);
825                 RETURN(count);
826         }
827
828         CFS_INIT_LIST_HEAD(&tmp);
829         if (cfs_parse_nidlist(kernbuf, count, &tmp) <= 0) {
830                 errmsg = "can't parse";
831                 GOTO(failed, rc = -EINVAL);
832         }
833
834         down_write(&mdt->mdt_squash_sem);
835         if (!cfs_list_empty(&mdt->mdt_nosquash_nids)) {
836                 cfs_free_nidlist(&mdt->mdt_nosquash_nids);
837                 OBD_FREE(mdt->mdt_nosquash_str, mdt->mdt_nosquash_strlen);
838         }
839         mdt->mdt_nosquash_str = kernbuf;
840         mdt->mdt_nosquash_strlen = count + 1;
841         cfs_list_splice(&tmp, &mdt->mdt_nosquash_nids);
842
843         LCONSOLE_INFO("%s: nosquash_nids is set to %s\n",
844                       mdt_obd_name(mdt), kernbuf);
845         up_write(&mdt->mdt_squash_sem);
846         RETURN(count);
847
848 failed:
849         CWARN("%s: failed to set nosquash_nids to \"%s\", %s: rc %d\n",
850               mdt_obd_name(mdt), kernbuf, errmsg, rc);
851         if (kernbuf)
852                 OBD_FREE(kernbuf, count + 1);
853         RETURN(rc);
854 }
855
856 static int lprocfs_rd_mdt_som(char *page, char **start, off_t off,
857                               int count, int *eof, void *data)
858 {
859         struct obd_device *obd = data;
860         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
861
862         return snprintf(page, count, "%sabled\n",
863                         mdt->mdt_som_conf ? "en" : "dis");
864 }
865
866 static int lprocfs_wr_mdt_som(struct file *file, const char __user *buffer,
867                               unsigned long count, void *data)
868 {
869         struct obd_export *exp;
870         struct obd_device *obd = data;
871         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
872         char kernbuf[16];
873         unsigned long val = 0;
874
875         if (count > (sizeof(kernbuf) - 1))
876                 return -EINVAL;
877
878         if (copy_from_user(kernbuf, buffer, count))
879                 return -EFAULT;
880
881         kernbuf[count] = '\0';
882
883         if (!strcmp(kernbuf, "enabled"))
884                 val = 1;
885         else if (strcmp(kernbuf, "disabled"))
886                 return -EINVAL;
887
888         if (mdt->mdt_som_conf == val)
889                 return count;
890
891         if (!obd->obd_process_conf) {
892                 CERROR("Temporary SOM change is not supported, use lctl "
893                        "conf_param for permanent setting\n");
894                 return count;
895         }
896
897         /* 1 stands for self export. */
898         cfs_list_for_each_entry(exp, &obd->obd_exports, exp_obd_chain) {
899                 if (exp == obd->obd_self_export)
900                         continue;
901                 if (exp_connect_flags(exp) & OBD_CONNECT_MDS_MDS)
902                         continue;
903                 /* Some clients are already connected, skip the change */
904                 LCONSOLE_INFO("%s is already connected, SOM will be %s on "
905                               "the next mount\n", exp->exp_client_uuid.uuid,
906                               val ? "enabled" : "disabled");
907                 return count;
908         }
909
910         mdt->mdt_som_conf = val;
911         LCONSOLE_INFO("Enabling SOM\n");
912
913         return count;
914 }
915
916 static int lprocfs_rd_enable_remote_dir(char *page, char **start, off_t off,
917                                         int count, int *eof, void *data)
918 {
919         struct obd_device *obd = data;
920         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
921
922         return snprintf(page, count, "%u\n", mdt->mdt_enable_remote_dir);
923 }
924
925 static int lprocfs_wr_enable_remote_dir(struct file *file,
926                                         const char __user *buffer,
927                                         unsigned long count, void *data)
928 {
929         struct obd_device *obd = data;
930         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
931         __u32 val;
932         int rc;
933
934         rc = lprocfs_write_helper(buffer, count, &val);
935         if (rc)
936                 return rc;
937
938         if (val > 1)
939                 return -ERANGE;
940
941         mdt->mdt_enable_remote_dir = val;
942         return count;
943 }
944
945 static int lprocfs_rd_enable_remote_dir_gid(char *page, char **start, off_t off,
946                                             int count, int *eof, void *data)
947 {
948         struct obd_device *obd = data;
949         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
950
951         return snprintf(page, count, "%d\n",
952                         (int)mdt->mdt_enable_remote_dir_gid);
953 }
954
955 static int lprocfs_wr_enable_remote_dir_gid(struct file *file,
956                                             const char __user *buffer,
957                                             unsigned long count, void *data)
958 {
959         struct obd_device *obd = data;
960         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
961         __u32 val;
962         int rc;
963
964         rc = lprocfs_write_helper(buffer, count, &val);
965         if (rc)
966                 return rc;
967
968         mdt->mdt_enable_remote_dir_gid = val;
969         return count;
970 }
971
972 static struct lprocfs_vars lprocfs_mdt_obd_vars[] = {
973         { "uuid",                       lprocfs_rd_uuid, NULL,
974                                         NULL, NULL, 0 },
975         { "recovery_status",            lprocfs_obd_rd_recovery_status, NULL,
976                                         NULL, NULL, 0 },
977         { "num_exports",                lprocfs_rd_num_exports, NULL,
978                                         NULL, NULL, 0 },
979         { "identity_expire",            lprocfs_rd_identity_expire,
980                                         lprocfs_wr_identity_expire,
981                                         NULL, NULL, 0 },
982         { "identity_acquire_expire",    lprocfs_rd_identity_acquire_expire,
983                                         lprocfs_wr_identity_acquire_expire,
984                                         NULL, NULL, 0 },
985         { "identity_upcall",            lprocfs_rd_identity_upcall,
986                                         lprocfs_wr_identity_upcall,
987                                         NULL, NULL, 0 },
988         { "identity_flush",             NULL, lprocfs_wr_identity_flush,
989                                         NULL, NULL, 0 },
990         { "identity_info",              NULL, lprocfs_wr_identity_info,
991                                         NULL, NULL, 0 },
992         { "capa",                       lprocfs_rd_capa,
993                                         lprocfs_wr_capa,
994                                         NULL, NULL, 0 },
995         { "capa_timeout",               lprocfs_rd_capa_timeout,
996                                         lprocfs_wr_capa_timeout,
997                                         NULL, NULL, 0 },
998         { "capa_key_timeout",           lprocfs_rd_ck_timeout,
999                                         lprocfs_wr_ck_timeout,
1000                                         NULL, NULL, 0 },
1001         { "capa_count",                 lprocfs_rd_capa_count, NULL,
1002                                         NULL, NULL, 0 },
1003         { "site_stats",                 lprocfs_rd_site_stats, NULL,
1004                                         NULL, NULL, 0 },
1005         { "evict_client",               NULL, lprocfs_mdt_wr_evict_client,
1006                                         NULL, NULL, 0 },
1007         { "hash_stats",                 lprocfs_obd_rd_hash, NULL,
1008                                         NULL, NULL, 0 },
1009         { "sec_level",                  lprocfs_rd_sec_level,
1010                                         lprocfs_wr_sec_level,
1011                                         NULL, NULL, 0 },
1012         { "commit_on_sharing",          lprocfs_rd_cos, lprocfs_wr_cos,
1013                                         NULL, NULL, 0 },
1014         { "root_squash",                lprocfs_rd_root_squash,
1015                                         lprocfs_wr_root_squash,
1016                                         NULL, NULL, 0 },
1017         { "nosquash_nids",              lprocfs_rd_nosquash_nids,
1018                                         lprocfs_wr_nosquash_nids,
1019                                         NULL, NULL, 0 },
1020         { "som",                        lprocfs_rd_mdt_som,
1021                                         lprocfs_wr_mdt_som,
1022                                         NULL, NULL, 0 },
1023         { "instance",                   lprocfs_target_rd_instance, NULL,
1024                                         NULL, NULL, 0},
1025         { "ir_factor",                  lprocfs_obd_rd_ir_factor,
1026                                         lprocfs_obd_wr_ir_factor,
1027                                         NULL, NULL, 0 },
1028         { "job_cleanup_interval",       lprocfs_rd_job_interval,
1029                                         lprocfs_wr_job_interval,
1030                                         NULL, NULL, 0 },
1031         { "enable_remote_dir",          lprocfs_rd_enable_remote_dir,
1032                                         lprocfs_wr_enable_remote_dir,
1033                                         NULL, NULL, 0},
1034         { "enable_remote_dir_gid",      lprocfs_rd_enable_remote_dir_gid,
1035                                         lprocfs_wr_enable_remote_dir_gid,
1036                                         NULL, NULL, 0},
1037         { "hsm_control",                lprocfs_rd_hsm_cdt_control,
1038                                         lprocfs_wr_hsm_cdt_control,
1039                                         NULL, NULL, 0 },
1040         { 0 }
1041 };
1042
1043 static struct lprocfs_vars lprocfs_mdt_module_vars[] = {
1044         { "num_refs",                   lprocfs_rd_numrefs, NULL,
1045                                         NULL, NULL, 0 },
1046         { 0 }
1047 };
1048
1049 void lprocfs_mdt_init_vars(struct lprocfs_static_vars *lvars)
1050 {
1051         lvars->module_vars  = lprocfs_mdt_module_vars;
1052         lvars->obd_vars     = lprocfs_mdt_obd_vars;
1053 }
1054
1055 struct lprocfs_vars lprocfs_mds_obd_vars[] = {
1056         { "uuid",       lprocfs_rd_uuid, NULL, NULL, NULL, 0 },
1057         { 0 }
1058 };
1059
1060 struct lprocfs_vars lprocfs_mds_module_vars[] = {
1061         { "num_refs",   lprocfs_rd_numrefs, NULL, NULL, NULL, 0 },
1062         { 0 }
1063 };
1064
1065 int lprocfs_mdt_print_open_files(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1066                                  cfs_hlist_node_t *hnode, void *v)
1067 {
1068         struct obd_export       *exp = cfs_hash_object(hs, hnode);
1069         struct seq_file         *seq = v;
1070
1071         if (exp->exp_lock_hash != NULL) {
1072                 struct mdt_export_data  *med = &exp->exp_mdt_data;
1073                 struct mdt_file_data    *mfd;
1074
1075                 spin_lock(&med->med_open_lock);
1076                 cfs_list_for_each_entry(mfd, &med->med_open_head, mfd_list) {
1077                         seq_printf(seq, DFID"\n",
1078                                    PFID(mdt_object_fid(mfd->mfd_object)));
1079                 }
1080                 spin_unlock(&med->med_open_lock);
1081         }
1082
1083         return 0;
1084 }
1085
1086 int lprocfs_mdt_open_files_seq_show(struct seq_file *seq, void *v)
1087 {
1088         struct nid_stat *stats = seq->private;
1089         struct obd_device *obd = stats->nid_obd;
1090
1091         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1092                               lprocfs_mdt_print_open_files, seq);
1093
1094         return 0;
1095 }
1096
1097 int lprocfs_mdt_open_files_seq_open(struct inode *inode, struct file *file)
1098 {
1099         struct proc_dir_entry   *dp = PDE(inode);
1100         struct seq_file         *seq;
1101         struct nid_stat         *tmp;
1102         int                     rc;
1103
1104         if (LPROCFS_ENTRY_CHECK(dp))
1105                 return -ENOENT;
1106
1107         tmp = dp->data;
1108         rc = single_open(file, &lprocfs_mdt_open_files_seq_show, NULL);
1109         if (rc != 0)
1110                 return rc;
1111
1112         seq = file->private_data;
1113         seq->private = tmp;
1114
1115         return 0;
1116 }
1117
1118 void mdt_counter_incr(struct ptlrpc_request *req, int opcode)
1119 {
1120         struct obd_export *exp = req->rq_export;
1121
1122         if (exp->exp_obd && exp->exp_obd->obd_md_stats)
1123                 lprocfs_counter_incr(exp->exp_obd->obd_md_stats, opcode);
1124         if (exp->exp_nid_stats && exp->exp_nid_stats->nid_stats != NULL)
1125                 lprocfs_counter_incr(exp->exp_nid_stats->nid_stats, opcode);
1126         if (exp->exp_obd && exp->exp_obd->u.obt.obt_jobstats.ojs_hash &&
1127             (exp_connect_flags(exp) & OBD_CONNECT_JOBSTATS))
1128                 lprocfs_job_stats_log(exp->exp_obd,
1129                                       lustre_msg_get_jobid(req->rq_reqmsg),
1130                                       opcode, 1);
1131 }
1132
1133 void mdt_stats_counter_init(struct lprocfs_stats *stats)
1134 {
1135         lprocfs_counter_init(stats, LPROC_MDT_OPEN, 0, "open", "reqs");
1136         lprocfs_counter_init(stats, LPROC_MDT_CLOSE, 0, "close", "reqs");
1137         lprocfs_counter_init(stats, LPROC_MDT_MKNOD, 0, "mknod", "reqs");
1138         lprocfs_counter_init(stats, LPROC_MDT_LINK, 0, "link", "reqs");
1139         lprocfs_counter_init(stats, LPROC_MDT_UNLINK, 0, "unlink", "reqs");
1140         lprocfs_counter_init(stats, LPROC_MDT_MKDIR, 0, "mkdir", "reqs");
1141         lprocfs_counter_init(stats, LPROC_MDT_RMDIR, 0, "rmdir", "reqs");
1142         lprocfs_counter_init(stats, LPROC_MDT_RENAME, 0, "rename", "reqs");
1143         lprocfs_counter_init(stats, LPROC_MDT_GETATTR, 0, "getattr", "reqs");
1144         lprocfs_counter_init(stats, LPROC_MDT_SETATTR, 0, "setattr", "reqs");
1145         lprocfs_counter_init(stats, LPROC_MDT_GETXATTR, 0, "getxattr", "reqs");
1146         lprocfs_counter_init(stats, LPROC_MDT_SETXATTR, 0, "setxattr", "reqs");
1147         lprocfs_counter_init(stats, LPROC_MDT_STATFS, 0, "statfs", "reqs");
1148         lprocfs_counter_init(stats, LPROC_MDT_SYNC, 0, "sync", "reqs");
1149         lprocfs_counter_init(stats, LPROC_MDT_SAMEDIR_RENAME, 0,
1150                              "samedir_rename", "reqs");
1151         lprocfs_counter_init(stats, LPROC_MDT_CROSSDIR_RENAME, 0,
1152                              "crossdir_rename", "reqs");
1153 }