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