Whamcloud - gitweb
- make HEAD from b_post_cmd3
[fs/lustre-release.git] / lustre / mdt / mdt_lproc.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2004-2006 Cluster File Systems, Inc.
5  *   Author: Lai Siyao <lsy@clusterfs.com>
6  *   Author: Fan Yong <fanyong@clusterfs.com>
7  *
8  *   This file is part of the Lustre file system, http://www.lustre.org
9  *   Lustre is a trademark of Cluster File Systems, Inc.
10  *
11  *   You may have signed or agreed to another license before downloading
12  *   this software.  If so, you are bound by the terms and conditions
13  *   of that agreement, and the following does not apply to you.  See the
14  *   LICENSE file included with this distribution for more information.
15  *
16  *   If you did not agree to a different license, then this copy of Lustre
17  *   is open source software; you can redistribute it and/or modify it
18  *   under the terms of version 2 of the GNU General Public License as
19  *   published by the Free Software Foundation.
20  *
21  *   In either case, Lustre is distributed in the hope that it will be
22  *   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
23  *   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  *   license text for more details.
25  *
26  */
27
28 #ifndef EXPORT_SYMTAB
29 # define EXPORT_SYMTAB
30 #endif
31 #define DEBUG_SUBSYSTEM S_MDS
32
33 #include <linux/version.h>
34 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
35 #include <asm/statfs.h>
36 #endif
37
38 #include <linux/module.h>
39
40 /* LUSTRE_VERSION_CODE */
41 #include <lustre_ver.h>
42 /*
43  * struct OBD_{ALLOC,FREE}*()
44  * MDT_FAIL_CHECK
45  */
46 #include <obd_support.h>
47 /* struct obd_export */
48 #include <lustre_export.h>
49 /* struct obd_device */
50 #include <obd.h>
51 #include <obd_class.h>
52 #include <lustre_mds.h>
53 #include <lustre_mdt.h>
54 #include <lprocfs_status.h>
55 #include <lu_time.h>
56 #include "mdt_internal.h"
57
58 static const char *mdt_proc_names[LPROC_MDT_NR] = {
59 };
60
61 int mdt_procfs_init(struct mdt_device *mdt, const char *name)
62 {
63         struct lu_device *ld = &mdt->mdt_md_dev.md_lu_dev;
64         int result;
65         ENTRY;
66
67         LASSERT(name != NULL);
68         mdt->mdt_proc_entry = ld->ld_obd->obd_proc_entry;
69         LASSERT(mdt->mdt_proc_entry != NULL);
70
71         result = lu_time_init(&mdt->mdt_stats, mdt->mdt_proc_entry,
72                               mdt_proc_names, ARRAY_SIZE(mdt_proc_names));
73         if (result == 0)
74                 result = lu_time_named_init(&ld->ld_site->ls_time_stats,
75                                             "site_time", mdt->mdt_proc_entry,
76                                             lu_time_names,
77                                             ARRAY_SIZE(lu_time_names));
78         RETURN(result);
79 }
80
81 int mdt_procfs_fini(struct mdt_device *mdt)
82 {
83         struct lu_device *ld = &mdt->mdt_md_dev.md_lu_dev;
84         lu_time_fini(&ld->ld_site->ls_time_stats);
85         lu_time_fini(&mdt->mdt_stats);
86         mdt->mdt_proc_entry = NULL;
87         RETURN(0);
88 }
89
90 void mdt_time_start(const struct mdt_thread_info *info)
91 {
92         lu_lprocfs_time_start(info->mti_env);
93 }
94
95 void mdt_time_end(const struct mdt_thread_info *info, int idx)
96 {
97         lu_lprocfs_time_end(info->mti_env, info->mti_mdt->mdt_stats, idx);
98 }
99
100 static int lprocfs_rd_identity_expire(char *page, char **start, off_t off,
101                                       int count, int *eof, void *data)
102 {
103         struct obd_device *obd = data;
104         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
105
106         *eof = 1;
107         return snprintf(page, count, "%lu\n",
108                         mdt->mdt_identity_cache->uc_entry_expire / HZ);
109 }
110
111 static int lprocfs_wr_identity_expire(struct file *file, const char *buffer,
112                                       unsigned long count, void *data)
113 {
114         struct obd_device *obd = data;
115         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
116         int rc, val;
117
118         rc = lprocfs_write_helper(buffer, count, &val);
119         if (rc)
120                 return rc;
121
122         mdt->mdt_identity_cache->uc_entry_expire = val * HZ;
123         return count;
124 }
125
126 static int lprocfs_rd_identity_acquire_expire(char *page, char **start,
127                                               off_t off, int count, int *eof,
128                                               void *data)
129 {
130         struct obd_device *obd = data;
131         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
132
133         *eof = 1;
134         return snprintf(page, count, "%lu\n",
135                         mdt->mdt_identity_cache->uc_acquire_expire / HZ);
136 }
137
138 static int lprocfs_wr_identity_acquire_expire(struct file *file,
139                                               const char *buffer,
140                                               unsigned long count,
141                                               void *data)
142 {
143         struct obd_device *obd = data;
144         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
145         int rc, val;
146
147         rc = lprocfs_write_helper(buffer, count, &val);
148         if (rc)
149                 return rc;
150
151         mdt->mdt_identity_cache->uc_acquire_expire = val * HZ;
152         return count;
153 }
154
155 static int lprocfs_rd_identity_upcall(char *page, char **start, off_t off,
156                                       int count, int *eof, void *data)
157 {
158         struct obd_device *obd = data;
159         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
160
161         *eof = 1;
162         return snprintf(page, count, "%s\n",
163                         mdt->mdt_identity_cache->uc_upcall);
164 }
165
166 static int lprocfs_wr_identity_upcall(struct file *file, const char *buffer,
167                                       unsigned long count, void *data)
168 {
169         struct obd_device *obd = data;
170         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
171         struct upcall_cache *hash = mdt->mdt_identity_cache;
172         char kernbuf[UC_CACHE_UPCALL_MAXPATH] = { '\0' };
173
174         if (count >= UC_CACHE_UPCALL_MAXPATH) {
175                 CERROR("%s: identity upcall too long\n", obd->obd_name);
176                 return -EINVAL;
177         }
178
179         if (copy_from_user(kernbuf, buffer,
180                            min(count, UC_CACHE_UPCALL_MAXPATH - 1)))
181                 return -EFAULT;
182
183         /* Remove any extraneous bits from the upcall (e.g. linefeeds) */
184         sscanf(kernbuf, "%s", hash->uc_upcall);
185
186         if (strcmp(hash->uc_name, obd->obd_name) != 0)
187                 CWARN("%s: write to upcall name %s\n",
188                       obd->obd_name, hash->uc_upcall);
189         CWARN("%s: identity upcall set to %s\n", obd->obd_name, hash->uc_upcall);
190
191         return count;
192 }
193
194 static int lprocfs_wr_identity_flush(struct file *file, const char *buffer,
195                                      unsigned long count, void *data)
196 {
197         struct obd_device *obd = data;
198         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
199         int rc, uid;
200
201         rc = lprocfs_write_helper(buffer, count, &uid);
202         if (rc)
203                 return rc;
204
205         mdt_flush_identity(mdt->mdt_identity_cache, uid);
206         return count;
207 }
208
209 static int lprocfs_wr_identity_info(struct file *file, const char *buffer,
210                                     unsigned long count, void *data)
211 {
212         struct obd_device *obd = data;
213         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
214         struct identity_downcall_data sparam, *param = &sparam;
215         int size = 0, rc = 0;
216
217         if (count < sizeof(*param)) {
218                 CERROR("%s: invalid data size %lu\n", obd->obd_name, count);
219                 return count;
220         }
221
222         if (copy_from_user(&sparam, buffer, sizeof(sparam))) {
223                 CERROR("%s: bad identity data\n", obd->obd_name);
224                 GOTO(out, rc = -EFAULT);
225         }
226
227         if (sparam.idd_magic != IDENTITY_DOWNCALL_MAGIC) {
228                 CERROR("%s: MDS identity downcall bad params\n", obd->obd_name);
229                 GOTO(out, rc = -EINVAL);
230         }
231
232         if (sparam.idd_nperms > N_SETXID_PERMS_MAX) {
233                 CERROR("%s: perm count %d more than maximum %d\n",
234                        obd->obd_name, sparam.idd_nperms, N_SETXID_PERMS_MAX);
235                 GOTO(out, rc = -EINVAL);
236         }
237
238         if (sparam.idd_ngroups > NGROUPS_MAX) {
239                 CERROR("%s: group count %d more than maximum %d\n",
240                        obd->obd_name, sparam.idd_ngroups, NGROUPS_MAX);
241                 GOTO(out, rc = -EINVAL);
242         }
243
244         if (sparam.idd_ngroups) {
245                 size = offsetof(struct identity_downcall_data,
246                                 idd_groups[sparam.idd_ngroups]);
247                 OBD_ALLOC(param, size);
248                 if (!param) {
249                         CERROR("%s: fail to alloc %d bytes for uid %u"
250                                " with %d groups\n", obd->obd_name, size,
251                                sparam.idd_uid, sparam.idd_ngroups);
252                         param = &sparam;
253                         param->idd_ngroups = 0;
254                 } else if (copy_from_user(param, buffer, size)) {
255                         CERROR("%s: uid %u bad supplementary group data\n",
256                                obd->obd_name, sparam.idd_uid);
257                         OBD_FREE(param, size);
258                         param = &sparam;
259                         param->idd_ngroups = 0;
260                 }
261         }
262
263         rc = upcall_cache_downcall(mdt->mdt_identity_cache, param->idd_err,
264                                    param->idd_uid, param);
265
266 out:
267         if (param && (param != &sparam))
268                 OBD_FREE(param, size);
269
270         return rc ?: count;
271 }
272
273 static int lprocfs_rd_rmtacl_expire(char *page, char **start, off_t off,
274                                     int count, int *eof, void *data)
275 {
276         struct obd_device *obd = data;
277         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
278
279         *eof = 1;
280         return snprintf(page, count, "%lu\n",
281                         mdt->mdt_rmtacl_cache->uc_entry_expire / HZ);
282 }
283
284 static int lprocfs_wr_rmtacl_expire(struct file *file, const char *buffer,
285                                     unsigned long count, void *data)
286 {
287         struct obd_device *obd = data;
288         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
289         int rc, val;
290
291         rc = lprocfs_write_helper(buffer, count, &val);
292         if (rc)
293                 return rc;
294
295         mdt->mdt_rmtacl_cache->uc_entry_expire = val * HZ;
296         return count;
297 }
298
299 static int lprocfs_rd_rmtacl_acquire_expire(char *page, char **start,
300                                             off_t off, int count, int *eof,
301                                             void *data)
302 {
303         struct obd_device *obd = data;
304         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
305
306         *eof = 1;
307         return snprintf(page, count, "%lu\n",
308                         mdt->mdt_rmtacl_cache->uc_acquire_expire / HZ);
309 }
310
311 static int lprocfs_wr_rmtacl_acquire_expire(struct file *file,
312                                             const char *buffer,
313                                             unsigned long count,
314                                             void *data)
315 {
316         struct obd_device *obd = data;
317         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
318         int rc, val;
319
320         rc = lprocfs_write_helper(buffer, count, &val);
321         if (rc)
322                 return rc;
323
324         mdt->mdt_rmtacl_cache->uc_acquire_expire = val * HZ;
325         return count;
326 }
327
328 static int lprocfs_rd_rmtacl_upcall(char *page, char **start, off_t off,
329                                       int count, int *eof, void *data)
330 {
331         struct obd_device *obd = data;
332         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
333
334         *eof = 1;
335         return snprintf(page, count, "%s\n",
336                         mdt->mdt_rmtacl_cache->uc_upcall);
337 }
338
339 static int lprocfs_wr_rmtacl_upcall(struct file *file, const char *buffer,
340                                       unsigned long count, void *data)
341 {
342         struct obd_device *obd = data;
343         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
344         struct upcall_cache *hash = mdt->mdt_rmtacl_cache;
345         char kernbuf[UC_CACHE_UPCALL_MAXPATH] = { '\0' };
346
347         if (count >= UC_CACHE_UPCALL_MAXPATH) {
348                 CERROR("%s: remote ACL upcall too long\n", obd->obd_name);
349                 return -EINVAL;
350         }
351
352         if (copy_from_user(kernbuf, buffer,
353                            min(count, UC_CACHE_UPCALL_MAXPATH - 1)))
354                 return -EFAULT;
355
356         /* Remove any extraneous bits from the upcall (e.g. linefeeds) */
357         sscanf(kernbuf, "%s", hash->uc_upcall);
358
359         if (strcmp(hash->uc_name, obd->obd_name) != 0)
360                 CWARN("%s: write to upcall name %s\n",
361                       obd->obd_name, hash->uc_upcall);
362         CWARN("%s: remote ACL upcall set to %s\n", obd->obd_name, hash->uc_upcall);
363
364         return count;
365 }
366
367 static int lprocfs_wr_rmtacl_info(struct file *file, const char *buffer,
368                                   unsigned long count, void *data)
369 {
370         struct obd_device *obd = data;
371         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
372         struct rmtacl_downcall_data sparam, *param = &sparam;
373         int size = 0, rc = 0;
374
375         if (count < sizeof(*param)) {
376                 CERROR("%s: invalid data size %lu\n", obd->obd_name, count);
377                 return count;
378         }
379
380         if (copy_from_user(&sparam, buffer, sizeof(sparam))) {
381                 CERROR("%s: bad remote acl data\n", obd->obd_name);
382                 GOTO(out, rc = -EFAULT);
383         }
384
385         if (sparam.add_magic != RMTACL_DOWNCALL_MAGIC) {
386                 CERROR("%s: MDT remote acl downcall bad params\n", obd->obd_name);
387                 GOTO(out, rc = -EINVAL);
388         }
389
390         if (sparam.add_buflen) {
391                 size = offsetof(struct rmtacl_downcall_data,
392                                 add_buf[sparam.add_buflen]);
393                 OBD_ALLOC(param, size);
394                 if (!param) {
395                         CERROR("%s: fail to alloc %d bytes for ino "LPU64"\n",
396                                obd->obd_name, size, sparam.add_key);
397                         param = &sparam;
398                         param->add_buflen = 0;
399                 } else if (copy_from_user(param, buffer, size)) {
400                         CERROR("%s: ino "LPU64" bad remote acl data\n",
401                                obd->obd_name, sparam.add_key);
402                         OBD_FREE(param, size);
403                         param = &sparam;
404                         param->add_buflen = 0;
405                 }
406         }
407
408         rc = upcall_cache_downcall(mdt->mdt_rmtacl_cache, 0, param->add_key,
409                                    param);
410
411 out:
412         if (param && (param != &sparam))
413                 OBD_FREE(param, size);
414
415         return rc ?: count;
416 }
417
418 static int lprocfs_rd_rootsquash_uid(char *page, char **start, off_t off,
419                                  int count, int *eof, void *data)
420 {
421         struct obd_device *obd = data;
422         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
423         struct rootsquash_info *rsi = mdt->mdt_rootsquash_info;
424
425         *eof = 1;
426         return snprintf(page, count, "%u\n",
427                         rsi ? rsi->rsi_uid : 0);
428 }
429
430 static int lprocfs_wr_rootsquash_uid(struct file *file, const char *buffer,
431                                      unsigned long count, void *data)
432 {
433         struct obd_device *obd = data;
434         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
435         int val, rc;
436
437         rc = lprocfs_write_helper(buffer, count, &val);
438         if (rc)
439                 return rc;
440
441         if (!mdt->mdt_rootsquash_info)
442                 OBD_ALLOC_PTR(mdt->mdt_rootsquash_info);
443         if (!mdt->mdt_rootsquash_info)
444                 return -ENOMEM;
445
446         mdt->mdt_rootsquash_info->rsi_uid = val;
447         return count;
448 }
449
450 static int lprocfs_rd_rootsquash_gid(char *page, char **start, off_t off,
451                                  int count, int *eof, void *data)
452 {
453         struct obd_device *obd = data;
454         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
455         struct rootsquash_info *rsi = mdt->mdt_rootsquash_info;
456
457         *eof = 1;
458         return snprintf(page, count, "%u\n",
459                         rsi ? rsi->rsi_gid : 0);
460 }
461
462 static int lprocfs_wr_rootsquash_gid(struct file *file, const char *buffer,
463                                      unsigned long count, void *data)
464 {
465         struct obd_device *obd = data;
466         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
467         int val, rc;
468
469         rc = lprocfs_write_helper(buffer, count, &val);
470         if (rc)
471                 return rc;
472
473         if (!mdt->mdt_rootsquash_info)
474                 OBD_ALLOC_PTR(mdt->mdt_rootsquash_info);
475         if (!mdt->mdt_rootsquash_info)
476                 return -ENOMEM;
477
478         mdt->mdt_rootsquash_info->rsi_gid = val;
479         return count;
480 }
481
482 static int lprocfs_rd_nosquash_nids(char *page, char **start, off_t off,
483                                        int count, int *eof, void *data)
484 {
485         struct obd_device *obd = data;
486         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
487         struct rootsquash_info *rsi = mdt->mdt_rootsquash_info;
488         int i, ret;
489
490         ret = snprintf(page, count, "rootsquash skip list:\n");
491         for (i = 0; rsi && (i < rsi->rsi_n_nosquash_nids); i++) {
492                 ret += snprintf(page + ret, count - ret, "%s\n",
493                                 libcfs_nid2str(rsi->rsi_nosquash_nids[i]));
494         }
495
496         *eof = 1;
497         return ret;
498 }
499
500 static inline void remove_newline(char *str)
501 {
502         int len = strlen(str);
503
504         if (str[len - 1] == '\n')
505                 str[len - 1] = '\0';
506 }
507
508 /* XXX: This macro is copied from lnet/libcfs/nidstring.c */
509 #define LNET_NIDSTR_SIZE   32      /* size of each one (see below for usage) */
510
511 static void do_process_nosquash_nids(struct mdt_device *m, char *buf)
512 {
513         struct rootsquash_info *rsi = m->mdt_rootsquash_info;
514         char str[LNET_NIDSTR_SIZE], *end;
515         lnet_nid_t nid;
516
517         LASSERT(rsi);
518         rsi->rsi_n_nosquash_nids = 0;
519         while (rsi->rsi_n_nosquash_nids < N_NOSQUASH_NIDS) {
520                 end = strchr(buf, ',');
521                 memset(str, 0, sizeof(str));
522                 if (end)
523                         strncpy(str, buf, min_t(int, sizeof(str), end - buf));
524                 else
525                         strncpy(str, buf, min_t(int, sizeof(str), strlen(buf)));
526
527                 if (!strcmp(str, "*")) {
528                         nid = LNET_NID_ANY;
529                 } else {
530                         nid = libcfs_str2nid(str);
531                         if (nid == LNET_NID_ANY)
532                                 goto ignore;
533                 }
534                 rsi->rsi_nosquash_nids[rsi->rsi_n_nosquash_nids++] = nid;
535 ignore:
536                 if (!end || (*(end + 1) == 0))
537                         return;
538                 buf = end + 1;
539         }
540 }
541
542 static int lprocfs_wr_nosquash_nids(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         char skips[LNET_NIDSTR_SIZE * N_NOSQUASH_NIDS] = "";
548         unsigned long size = sizeof(skips);
549
550         if (count > size) {
551                 CERROR("parameter exceeds max limit %lu\n", size);
552                 return -EINVAL;
553         }
554
555         if (copy_from_user(skips, buffer, min(size, count)))
556                 return -EFAULT;
557
558         if (!mdt->mdt_rootsquash_info)
559                 OBD_ALLOC_PTR(mdt->mdt_rootsquash_info);
560         if (!mdt->mdt_rootsquash_info)
561                 return -ENOMEM;
562
563         remove_newline(skips);
564         do_process_nosquash_nids(mdt, skips);
565         return count;
566 }
567
568 /* for debug only */
569 static int lprocfs_rd_capa(char *page, char **start, off_t off,
570                            int count, int *eof, void *data)
571 {
572         struct obd_device *obd = data;
573         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
574
575         return snprintf(page, count, "capability on: %s %s\n",
576                         mdt->mdt_opts.mo_oss_capa ? "oss" : "",
577                         mdt->mdt_opts.mo_mds_capa ? "mds" : "");
578 }
579
580 static int lprocfs_wr_capa(struct file *file, const char *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         if (val < 0 || val > 3) {
592                 CERROR("invalid capability mode, only 0/2/3 is accepted.\n"
593                        " 0:  disable fid capability\n"
594                        " 2:  enable MDS fid capability\n"
595                        " 3:  enable both MDS and OSS fid capability\n");
596                 return -EINVAL;
597         }
598
599         /* OSS fid capability needs enable both MDS and OSS fid capability on
600          * MDS */
601         if (val == 1) {
602                 CERROR("can't enable OSS fid capability only, you should use "
603                        "'3' to enable both MDS and OSS fid capability.\n");
604                 return -EINVAL;
605         }
606
607         mdt->mdt_opts.mo_oss_capa = (val & 0x1);
608         mdt->mdt_opts.mo_mds_capa = !!(val & 0x2);
609         mdt->mdt_capa_conf = 1;
610         LCONSOLE_INFO("MDS %s %s MDS fid capability.\n",
611                       obd->obd_name,
612                       mdt->mdt_opts.mo_mds_capa ? "enabled" : "disabled");
613         LCONSOLE_INFO("MDS %s %s OSS fid capability.\n",
614                       obd->obd_name,
615                       mdt->mdt_opts.mo_oss_capa ? "enabled" : "disabled");
616         return count;
617 }
618
619 static int lprocfs_rd_capa_count(char *page, char **start, off_t off,
620                                  int count, int *eof, void *data)
621 {
622         return snprintf(page, count, "%d %d\n",
623                         capa_count[CAPA_SITE_CLIENT],
624                         capa_count[CAPA_SITE_SERVER]);
625 }
626
627 static int lprocfs_rd_site_stats(char *page, char **start, off_t off,
628                                  int count, int *eof, void *data)
629 {
630         struct obd_device *obd = data;
631         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
632         struct lu_site    *s   = mdt->mdt_md_dev.md_lu_dev.ld_site;
633         int i;
634         int populated;
635
636         /*
637          * How many hash buckets are not-empty? Don't bother with locks: it's
638          * an estimation anyway.
639          */
640         for (i = 0, populated = 0; i < s->ls_hash_size; i++)
641                 populated += !hlist_empty(&s->ls_hash[i]);
642
643         return snprintf(page, count, "%d %d %d/%d %d %d %d %d %d %d\n",
644                         s->ls_total,
645                         s->ls_busy,
646                         populated,
647                         s->ls_hash_size,
648                         s->ls_stats.s_created,
649                         s->ls_stats.s_cache_hit,
650                         s->ls_stats.s_cache_miss,
651                         s->ls_stats.s_cache_check,
652                         s->ls_stats.s_cache_race,
653                         s->ls_stats.s_lru_purged);
654 }
655
656 static int lprocfs_rd_capa_timeout(char *page, char **start, off_t off,
657                                    int count, int *eof, void *data)
658 {
659         struct obd_device *obd = data;
660         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
661
662         return snprintf(page, count, "%lu\n", mdt->mdt_capa_timeout);
663 }
664
665 static int lprocfs_wr_capa_timeout(struct file *file, const char *buffer,
666                                    unsigned long count, void *data)
667 {
668         struct obd_device *obd = data;
669         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
670         int val, rc;
671
672         rc = lprocfs_write_helper(buffer, count, &val);
673         if (rc)
674                 return rc;
675
676         mdt->mdt_capa_timeout = (unsigned long)val;
677         mdt->mdt_capa_conf = 1;
678         return count;
679 }
680
681 static int lprocfs_rd_ck_timeout(char *page, char **start, off_t off, int count,
682                                  int *eof, void *data)
683 {
684         struct obd_device *obd = data;
685         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
686
687         return snprintf(page, count, "%lu\n", mdt->mdt_ck_timeout);
688 }
689
690 static int lprocfs_wr_ck_timeout(struct file *file, const char *buffer,
691                                  unsigned long count, void *data)
692 {
693         struct obd_device *obd = data;
694         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
695         int val, rc;
696
697         rc = lprocfs_write_helper(buffer, count, &val);
698         if (rc)
699                 return rc;
700
701         mdt->mdt_ck_timeout = (unsigned long)val;
702         mdt->mdt_capa_conf = 1;
703         return count;
704 }
705
706 static int lprocfs_mdt_wr_evict_client(struct file *file, const char *buffer,
707                                        unsigned long count, void *data)
708 {
709         char tmpbuf[sizeof(struct obd_uuid)];
710
711         sscanf(buffer, "%40s", tmpbuf);
712
713         if (strncmp(tmpbuf, "nid:", 4) != 0)
714                 return lprocfs_wr_evict_client(file, buffer, count, data);
715
716         CERROR("NOT implement evict client by nid %s\n", tmpbuf);
717
718         return count;
719 }
720
721 static struct lprocfs_vars lprocfs_mdt_obd_vars[] = {
722         { "uuid",                       lprocfs_rd_uuid,                 0, 0 },
723         { "recovery_status",            lprocfs_obd_rd_recovery_status,  0, 0 },
724         { "num_exports",                lprocfs_rd_num_exports,          0, 0 },
725         { "identity_expire",            lprocfs_rd_identity_expire,
726                                         lprocfs_wr_identity_expire,         0 },
727         { "identity_acquire_expire",    lprocfs_rd_identity_acquire_expire,
728                                         lprocfs_wr_identity_acquire_expire, 0 },
729         { "identity_upcall",            lprocfs_rd_identity_upcall,
730                                         lprocfs_wr_identity_upcall,         0 },
731         { "identity_flush",             0, lprocfs_wr_identity_flush,       0 },
732         { "identity_info",              0, lprocfs_wr_identity_info,        0 },
733         { "rmtacl_expire",              lprocfs_rd_rmtacl_expire,
734                                         lprocfs_wr_rmtacl_expire,           0 },
735         { "rmtacl_acquire_expire",      lprocfs_rd_rmtacl_acquire_expire,
736                                         lprocfs_wr_rmtacl_acquire_expire,   0 },
737         { "rmtacl_upcall",              lprocfs_rd_rmtacl_upcall,
738                                         lprocfs_wr_rmtacl_upcall,           0 },
739         { "rmtacl_info",                0, lprocfs_wr_rmtacl_info,          0 },
740         { "rootsquash_uid",             lprocfs_rd_rootsquash_uid,
741                                         lprocfs_wr_rootsquash_uid,          0 },
742         { "rootsquash_gid",             lprocfs_rd_rootsquash_gid,
743                                         lprocfs_wr_rootsquash_gid,          0 },
744         { "nosquash_nids",              lprocfs_rd_nosquash_nids,
745                                         lprocfs_wr_nosquash_nids,           0 },
746         { "capa",                       lprocfs_rd_capa,
747                                         lprocfs_wr_capa,                    0 },
748         { "capa_timeout",               lprocfs_rd_capa_timeout,
749                                         lprocfs_wr_capa_timeout,            0 },
750         { "capa_key_timeout",           lprocfs_rd_ck_timeout,
751                                         lprocfs_wr_ck_timeout,              0 },
752         { "capa_count",                 lprocfs_rd_capa_count,           0, 0 },
753         { "site_stats",                 lprocfs_rd_site_stats,           0, 0 },
754         { "evict_client",               0, lprocfs_mdt_wr_evict_client,     0 },
755         { 0 }
756 };
757
758 static struct lprocfs_vars lprocfs_mdt_module_vars[] = {
759         { "num_refs",                   lprocfs_rd_numrefs,              0, 0 },
760         { 0 }
761 };
762
763 LPROCFS_INIT_VARS(mdt, lprocfs_mdt_module_vars, lprocfs_mdt_obd_vars);