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