Whamcloud - gitweb
f1413981c30bf9785186b8c2901c2ab02259f0a8
[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  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
30  * Use is subject to license terms.
31  *
32  * Copyright (c) 2011 Whamcloud, Inc.
33  *
34  */
35 /*
36  * This file is part of Lustre, http://www.lustre.org/
37  * Lustre is a trademark of Sun Microsystems, Inc.
38  *
39  * lustre/mdt/mdt_lproc.c
40  *
41  * Author: Lai Siyao <lsy@clusterfs.com>
42  * Author: Fan Yong <fanyong@clusterfs.com>
43  */
44
45 #ifndef EXPORT_SYMTAB
46 # define EXPORT_SYMTAB
47 #endif
48 #define DEBUG_SUBSYSTEM S_MDS
49
50 #include <linux/version.h>
51 #include <asm/statfs.h>
52
53 #include <linux/module.h>
54
55 /* LUSTRE_VERSION_CODE */
56 #include <lustre_ver.h>
57 /*
58  * struct OBD_{ALLOC,FREE}*()
59  * MDT_FAIL_CHECK
60  */
61 #include <obd_support.h>
62 /* struct obd_export */
63 #include <lustre_export.h>
64 /* struct obd_device */
65 #include <obd.h>
66 #include <obd_class.h>
67 #include <lustre_mds.h>
68 #include <lustre_mdt.h>
69 #include <lprocfs_status.h>
70 #include <lu_time.h>
71 #include "mdt_internal.h"
72 #include <lnet/lib-lnet.h>
73
74 enum {
75         LPROC_MDT_NR
76 };
77 static const char *mdt_proc_names[LPROC_MDT_NR] = {
78 };
79
80 int mdt_procfs_init(struct mdt_device *mdt, const char *name)
81 {
82         struct lu_device *ld = &mdt->mdt_md_dev.md_lu_dev;
83         struct obd_device *obd = ld->ld_obd;
84         struct lprocfs_static_vars lvars;
85         int rc;
86         ENTRY;
87
88         LASSERT(name != NULL);
89
90         lprocfs_mdt_init_vars(&lvars);
91         rc = lprocfs_obd_setup(obd, lvars.obd_vars);
92         if (rc) {
93                 CERROR("Can't init lprocfs, rc %d\n", rc);
94                 return rc;
95         }
96         ptlrpc_lprocfs_register_obd(obd);
97
98         mdt->mdt_proc_entry = obd->obd_proc_entry;
99         LASSERT(mdt->mdt_proc_entry != NULL);
100
101         rc = lu_time_init(&mdt->mdt_stats, mdt->mdt_proc_entry,
102                           mdt_proc_names, ARRAY_SIZE(mdt_proc_names));
103         if (rc == 0)
104                 rc = lu_time_named_init(&ld->ld_site->ls_time_stats,
105                                         "site_time", mdt->mdt_proc_entry,
106                                          lu_time_names,
107                                          ARRAY_SIZE(lu_time_names));
108         if (rc)
109                 return rc;
110
111         obd->obd_proc_exports_entry = proc_mkdir("exports",
112                                                  obd->obd_proc_entry);
113         if (obd->obd_proc_exports_entry)
114                 lprocfs_add_simple(obd->obd_proc_exports_entry,
115                                    "clear", lprocfs_nid_stats_clear_read,
116                                    lprocfs_nid_stats_clear_write, obd, NULL);
117         rc = lprocfs_alloc_md_stats(obd, LPROC_MDT_LAST);
118         if (rc == 0)
119                 mdt_stats_counter_init(obd->md_stats);
120
121         RETURN(rc);
122 }
123
124 int mdt_procfs_fini(struct mdt_device *mdt)
125 {
126         struct lu_device *ld = &mdt->mdt_md_dev.md_lu_dev;
127         struct obd_device *obd = ld->ld_obd;
128
129         if (obd->obd_proc_exports_entry) {
130                 lprocfs_remove_proc_entry("clear", obd->obd_proc_exports_entry);
131                 obd->obd_proc_exports_entry = NULL;
132         }
133         lprocfs_free_per_client_stats(obd);
134         lprocfs_obd_cleanup(obd);
135         ptlrpc_lprocfs_unregister_obd(obd);
136         if (mdt->mdt_proc_entry) {
137                 lu_time_fini(&ld->ld_site->ls_time_stats);
138                 lu_time_fini(&mdt->mdt_stats);
139                 mdt->mdt_proc_entry = NULL;
140         }
141         lprocfs_free_md_stats(obd);
142         lprocfs_free_obd_stats(obd);
143
144         RETURN(0);
145 }
146
147 void mdt_time_start(const struct mdt_thread_info *info)
148 {
149         lu_lprocfs_time_start(info->mti_env);
150 }
151
152 void mdt_time_end(const struct mdt_thread_info *info, int idx)
153 {
154         lu_lprocfs_time_end(info->mti_env, info->mti_mdt->mdt_stats, idx);
155 }
156
157 static int lprocfs_rd_identity_expire(char *page, char **start, off_t off,
158                                       int count, int *eof, void *data)
159 {
160         struct obd_device *obd = data;
161         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
162
163         *eof = 1;
164         return snprintf(page, count, "%u\n",
165                         mdt->mdt_identity_cache->uc_entry_expire);
166 }
167
168 static int lprocfs_wr_identity_expire(struct file *file, const char *buffer,
169                                       unsigned long count, void *data)
170 {
171         struct obd_device *obd = data;
172         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
173         int rc, val;
174
175         rc = lprocfs_write_helper(buffer, count, &val);
176         if (rc)
177                 return rc;
178
179         mdt->mdt_identity_cache->uc_entry_expire = val;
180         return count;
181 }
182
183 static int lprocfs_rd_identity_acquire_expire(char *page, char **start,
184                                               off_t off, int count, int *eof,
185                                               void *data)
186 {
187         struct obd_device *obd = data;
188         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
189
190         *eof = 1;
191         return snprintf(page, count, "%u\n",
192                         mdt->mdt_identity_cache->uc_acquire_expire);
193 }
194
195 static int lprocfs_wr_identity_acquire_expire(struct file *file,
196                                               const char *buffer,
197                                               unsigned long count,
198                                               void *data)
199 {
200         struct obd_device *obd = data;
201         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
202         int rc, val;
203
204         rc = lprocfs_write_helper(buffer, count, &val);
205         if (rc)
206                 return rc;
207
208         mdt->mdt_identity_cache->uc_acquire_expire = val;
209         return count;
210 }
211
212 static int lprocfs_rd_identity_upcall(char *page, char **start, off_t off,
213                                       int count, int *eof, void *data)
214 {
215         struct obd_device *obd = data;
216         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
217         struct upcall_cache *hash = mdt->mdt_identity_cache;
218         int len;
219
220         *eof = 1;
221         cfs_read_lock(&hash->uc_upcall_rwlock);
222         len = snprintf(page, count, "%s\n", hash->uc_upcall);
223         cfs_read_unlock(&hash->uc_upcall_rwlock);
224         return len;
225 }
226
227 static int lprocfs_wr_identity_upcall(struct file *file, const char *buffer,
228                                       unsigned long count, void *data)
229 {
230         struct obd_device *obd = data;
231         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
232         struct upcall_cache *hash = mdt->mdt_identity_cache;
233         int rc;
234         char *kernbuf;
235
236         if (count >= UC_CACHE_UPCALL_MAXPATH) {
237                 CERROR("%s: identity upcall too long\n", obd->obd_name);
238                 return -EINVAL;
239         }
240         OBD_ALLOC(kernbuf, count + 1);
241         if (kernbuf == NULL)
242                 GOTO(failed, rc = -ENOMEM);
243         if (cfs_copy_from_user(kernbuf, buffer, count))
244                 GOTO(failed, rc = -EFAULT);
245
246         /* Remove any extraneous bits from the upcall (e.g. linefeeds) */
247         cfs_write_lock(&hash->uc_upcall_rwlock);
248         sscanf(kernbuf, "%s", hash->uc_upcall);
249         cfs_write_unlock(&hash->uc_upcall_rwlock);
250
251         if (strcmp(hash->uc_name, obd->obd_name) != 0)
252                 CWARN("%s: write to upcall name %s\n",
253                       obd->obd_name, hash->uc_upcall);
254
255         if (strcmp(hash->uc_upcall, "NONE") == 0 && mdt->mdt_opts.mo_acl)
256                 CWARN("%s: disable \"identity_upcall\" with ACL enabled maybe "
257                       "cause unexpected \"EACCESS\"\n", obd->obd_name);
258
259         CWARN("%s: identity upcall set to %s\n", obd->obd_name, hash->uc_upcall);
260         OBD_FREE(kernbuf, count + 1);
261         RETURN(count);
262
263  failed:
264         if (kernbuf)
265                 OBD_FREE(kernbuf, count + 1);
266         RETURN(rc);
267 }
268
269 static int lprocfs_wr_identity_flush(struct file *file, const char *buffer,
270                                      unsigned long count, void *data)
271 {
272         struct obd_device *obd = data;
273         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
274         int rc, uid;
275
276         rc = lprocfs_write_helper(buffer, count, &uid);
277         if (rc)
278                 return rc;
279
280         mdt_flush_identity(mdt->mdt_identity_cache, uid);
281         return count;
282 }
283
284 static int lprocfs_wr_identity_info(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         struct identity_downcall_data *param;
290         int size = sizeof(*param), rc, checked = 0;
291
292 again:
293         if (count < size) {
294                 CERROR("%s: invalid data count = %lu, size = %d\n",
295                        obd->obd_name, count, size);
296                 return -EINVAL;
297         }
298
299         OBD_ALLOC(param, size);
300         if (param == NULL)
301                 return -ENOMEM;
302
303         if (cfs_copy_from_user(param, buffer, size)) {
304                 CERROR("%s: bad identity data\n", obd->obd_name);
305                 GOTO(out, rc = -EFAULT);
306         }
307
308         if (checked == 0) {
309                 checked = 1;
310                 if (param->idd_magic != IDENTITY_DOWNCALL_MAGIC) {
311                         CERROR("%s: MDS identity downcall bad params\n",
312                                obd->obd_name);
313                         GOTO(out, rc = -EINVAL);
314                 }
315
316                 if (param->idd_nperms > N_PERMS_MAX) {
317                         CERROR("%s: perm count %d more than maximum %d\n",
318                                obd->obd_name, param->idd_nperms, N_PERMS_MAX);
319                         GOTO(out, rc = -EINVAL);
320                 }
321
322                 if (param->idd_ngroups > NGROUPS_MAX) {
323                         CERROR("%s: group count %d more than maximum %d\n",
324                                obd->obd_name, param->idd_ngroups, NGROUPS_MAX);
325                         GOTO(out, rc = -EINVAL);
326                 }
327
328                 if (param->idd_ngroups) {
329                         rc = param->idd_ngroups; /* save idd_ngroups */
330                         OBD_FREE(param, size);
331                         size = offsetof(struct identity_downcall_data,
332                                         idd_groups[rc]);
333                         goto again;
334                 }
335         }
336
337         rc = upcall_cache_downcall(mdt->mdt_identity_cache, param->idd_err,
338                                    param->idd_uid, param);
339
340 out:
341         if (param != NULL)
342                 OBD_FREE(param, size);
343
344         return rc ? rc : count;
345 }
346
347 /* for debug only */
348 static int lprocfs_rd_capa(char *page, char **start, off_t off,
349                            int count, int *eof, void *data)
350 {
351         struct obd_device *obd = data;
352         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
353
354         return snprintf(page, count, "capability on: %s %s\n",
355                         mdt->mdt_opts.mo_oss_capa ? "oss" : "",
356                         mdt->mdt_opts.mo_mds_capa ? "mds" : "");
357 }
358
359 static int lprocfs_wr_capa(struct file *file, const char *buffer,
360                            unsigned long count, void *data)
361 {
362         struct obd_device *obd = data;
363         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
364         int val, rc;
365
366         rc = lprocfs_write_helper(buffer, count, &val);
367         if (rc)
368                 return rc;
369
370         if (val < 0 || val > 3) {
371                 CERROR("invalid capability mode, only 0/2/3 is accepted.\n"
372                        " 0:  disable fid capability\n"
373                        " 2:  enable MDS fid capability\n"
374                        " 3:  enable both MDS and OSS fid capability\n");
375                 return -EINVAL;
376         }
377
378         /* OSS fid capability needs enable both MDS and OSS fid capability on
379          * MDS */
380         if (val == 1) {
381                 CERROR("can't enable OSS fid capability only, you should use "
382                        "'3' to enable both MDS and OSS fid capability.\n");
383                 return -EINVAL;
384         }
385
386         mdt->mdt_opts.mo_oss_capa = (val & 0x1);
387         mdt->mdt_opts.mo_mds_capa = !!(val & 0x2);
388         mdt->mdt_capa_conf = 1;
389         LCONSOLE_INFO("MDS %s %s MDS fid capability.\n",
390                       obd->obd_name,
391                       mdt->mdt_opts.mo_mds_capa ? "enabled" : "disabled");
392         LCONSOLE_INFO("MDS %s %s OSS fid capability.\n",
393                       obd->obd_name,
394                       mdt->mdt_opts.mo_oss_capa ? "enabled" : "disabled");
395         return count;
396 }
397
398 static int lprocfs_rd_capa_count(char *page, char **start, off_t off,
399                                  int count, int *eof, void *data)
400 {
401         return snprintf(page, count, "%d %d\n",
402                         capa_count[CAPA_SITE_CLIENT],
403                         capa_count[CAPA_SITE_SERVER]);
404 }
405
406 static int lprocfs_rd_site_stats(char *page, char **start, off_t off,
407                                  int count, int *eof, void *data)
408 {
409         struct obd_device *obd = data;
410         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
411
412         return lu_site_stats_print(mdt_lu_site(mdt), page, count);
413 }
414
415 static int lprocfs_rd_capa_timeout(char *page, char **start, off_t off,
416                                    int count, int *eof, void *data)
417 {
418         struct obd_device *obd = data;
419         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
420
421         return snprintf(page, count, "%lu\n", mdt->mdt_capa_timeout);
422 }
423
424 static int lprocfs_wr_capa_timeout(struct file *file, const char *buffer,
425                                    unsigned long count, void *data)
426 {
427         struct obd_device *obd = data;
428         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
429         int val, rc;
430
431         rc = lprocfs_write_helper(buffer, count, &val);
432         if (rc)
433                 return rc;
434
435         mdt->mdt_capa_timeout = (unsigned long)val;
436         mdt->mdt_capa_conf = 1;
437         return count;
438 }
439
440 static int lprocfs_rd_ck_timeout(char *page, char **start, off_t off, int count,
441                                  int *eof, void *data)
442 {
443         struct obd_device *obd = data;
444         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
445
446         return snprintf(page, count, "%lu\n", mdt->mdt_ck_timeout);
447 }
448
449 static int lprocfs_wr_ck_timeout(struct file *file, const char *buffer,
450                                  unsigned long count, void *data)
451 {
452         struct obd_device *obd = data;
453         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
454         int val, rc;
455
456         rc = lprocfs_write_helper(buffer, count, &val);
457         if (rc)
458                 return rc;
459
460         mdt->mdt_ck_timeout = (unsigned long)val;
461         mdt->mdt_capa_conf = 1;
462         return count;
463 }
464
465 static int lprocfs_mdt_wr_evict_client(struct file *file, const char *buffer,
466                                        unsigned long count, void *data)
467 {
468         char tmpbuf[sizeof(struct obd_uuid)];
469
470         sscanf(buffer, "%40s", tmpbuf);
471
472         if (strncmp(tmpbuf, "nid:", 4) != 0)
473                 return lprocfs_wr_evict_client(file, buffer, count, data);
474
475         CERROR("NOT implement evict client by nid %s\n", tmpbuf);
476
477         return count;
478 }
479
480 static int lprocfs_rd_sec_level(char *page, char **start, off_t off,
481                                 int count, int *eof, void *data)
482 {
483         struct obd_device *obd = data;
484         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
485
486         return snprintf(page, count, "%d\n", mdt->mdt_sec_level);
487 }
488
489 static int lprocfs_wr_sec_level(struct file *file, const char *buffer,
490                                 unsigned long count, void *data)
491 {
492         struct obd_device *obd = data;
493         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
494         int val, rc;
495
496         rc = lprocfs_write_helper(buffer, count, &val);
497         if (rc)
498                 return rc;
499
500         if (val > LUSTRE_SEC_ALL || val < LUSTRE_SEC_NONE)
501                 return -EINVAL;
502
503         if (val == LUSTRE_SEC_SPECIFY) {
504                 CWARN("security level %d will be supported in future.\n",
505                       LUSTRE_SEC_SPECIFY);
506                 return -EINVAL;
507         }
508
509         mdt->mdt_sec_level = val;
510         return count;
511 }
512
513 static int lprocfs_rd_cos(char *page, char **start, off_t off,
514                               int count, int *eof, void *data)
515 {
516         struct obd_device *obd = data;
517         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
518
519         return snprintf(page, count, "%u\n", mdt_cos_is_enabled(mdt));
520 }
521
522 static int lprocfs_wr_cos(struct file *file, const char *buffer,
523                                   unsigned long count, void *data)
524 {
525         struct obd_device *obd = data;
526         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
527         int val, rc;
528
529         rc = lprocfs_write_helper(buffer, count, &val);
530         if (rc)
531                 return rc;
532         mdt_enable_cos(mdt, val);
533         return count;
534 }
535
536 static int lprocfs_rd_root_squash(char *page, char **start, off_t off,
537                                   int count, int *eof, void *data)
538 {
539         struct obd_device *obd = data;
540         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
541
542         return snprintf(page, count, "%u:%u\n", mdt->mdt_squash_uid,
543                         mdt->mdt_squash_gid);
544 }
545
546 static int safe_strtoul(const char *str, char **endp, unsigned long *res)
547 {
548         char n[24];
549
550         *res = simple_strtoul(str, endp, 0);
551         if (str == *endp)
552                 return 1;
553
554         sprintf(n, "%lu", *res);
555         if (strncmp(n, str, *endp - str))
556                 /* overflow */
557                 return 1;
558         return 0;
559 }
560
561 static int lprocfs_wr_root_squash(struct file *file, const char *buffer,
562                                   unsigned long count, void *data)
563 {
564         struct obd_device *obd = data;
565         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
566         int rc;
567         char kernbuf[50], *tmp, *end, *errmsg;
568         unsigned long uid, gid;
569         int nouid, nogid;
570         ENTRY;
571
572         if (count >= sizeof(kernbuf)) {
573                 errmsg = "string too long";
574                 GOTO(failed, rc = -EINVAL);
575         }
576         if (cfs_copy_from_user(kernbuf, buffer, count)) {
577                 errmsg = "bad address";
578                 GOTO(failed, rc = -EFAULT);
579         }
580         kernbuf[count] = '\0';
581
582         nouid = nogid = 0;
583         if (safe_strtoul(buffer, &tmp, &uid)) {
584                 uid = mdt->mdt_squash_uid;
585                 nouid = 1;
586         }
587
588         /* skip ':' */
589         if (*tmp == ':') {
590                 tmp++;
591                 if (safe_strtoul(tmp, &end, &gid)) {
592                         gid = mdt->mdt_squash_gid;
593                         nogid = 1;
594                 }
595         } else {
596                 gid = mdt->mdt_squash_gid;
597                 nogid = 1;
598         }
599
600         mdt->mdt_squash_uid = uid;
601         mdt->mdt_squash_gid = gid;
602
603         if (nouid && nogid) {
604                 errmsg = "needs uid:gid format";
605                 GOTO(failed, rc = -EINVAL);
606         }
607
608         LCONSOLE_INFO("%s: root_squash is set to %u:%u\n",
609                       obd->obd_name,
610                       mdt->mdt_squash_uid,  mdt->mdt_squash_gid);
611         RETURN(count);
612
613  failed:
614         CWARN("%s: failed to set root_squash to \"%s\", %s: rc %d\n",
615               obd->obd_name, buffer, errmsg, rc);
616         RETURN(rc);
617 }
618
619 static int lprocfs_rd_nosquash_nids(char *page, char **start, off_t off,
620                                     int count, int *eof, void *data)
621 {
622         struct obd_device *obd = data;
623         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
624
625         if (mdt->mdt_nosquash_str)
626                 return snprintf(page, count, "%s\n", mdt->mdt_nosquash_str);
627         return snprintf(page, count, "NONE\n");
628 }
629
630 static int lprocfs_wr_nosquash_nids(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 rc;
636         char *kernbuf, *errmsg;
637         cfs_list_t tmp;
638         ENTRY;
639
640         OBD_ALLOC(kernbuf, count + 1);
641         if (kernbuf == NULL) {
642                 errmsg = "no memory";
643                 GOTO(failed, rc = -ENOMEM);
644         }
645         if (cfs_copy_from_user(kernbuf, buffer, count)) {
646                 errmsg = "bad address";
647                 GOTO(failed, rc = -EFAULT);
648         }
649         kernbuf[count] = '\0';
650
651         if (!strcmp(kernbuf, "NONE") || !strcmp(kernbuf, "clear")) {
652                 /* empty string is special case */
653                 cfs_down_write(&mdt->mdt_squash_sem);
654                 if (!cfs_list_empty(&mdt->mdt_nosquash_nids)) {
655                         cfs_free_nidlist(&mdt->mdt_nosquash_nids);
656                         OBD_FREE(mdt->mdt_nosquash_str,
657                                  mdt->mdt_nosquash_strlen);
658                         mdt->mdt_nosquash_str = NULL;
659                         mdt->mdt_nosquash_strlen = 0;
660                 }
661                 cfs_up_write(&mdt->mdt_squash_sem);
662                 LCONSOLE_INFO("%s: nosquash_nids is cleared\n",
663                               obd->obd_name);
664                 OBD_FREE(kernbuf, count + 1);
665                 RETURN(count);
666         }
667
668         CFS_INIT_LIST_HEAD(&tmp);
669         if (cfs_parse_nidlist(kernbuf, count, &tmp) <= 0) {
670                 errmsg = "can't parse";
671                 GOTO(failed, rc = -EINVAL);
672         }
673
674         cfs_down_write(&mdt->mdt_squash_sem);
675         if (!cfs_list_empty(&mdt->mdt_nosquash_nids)) {
676                 cfs_free_nidlist(&mdt->mdt_nosquash_nids);
677                 OBD_FREE(mdt->mdt_nosquash_str, mdt->mdt_nosquash_strlen);
678         }
679         mdt->mdt_nosquash_str = kernbuf;
680         mdt->mdt_nosquash_strlen = count + 1;
681         cfs_list_splice(&tmp, &mdt->mdt_nosquash_nids);
682
683         LCONSOLE_INFO("%s: nosquash_nids is set to %s\n",
684                       obd->obd_name, kernbuf);
685         cfs_up_write(&mdt->mdt_squash_sem);
686         RETURN(count);
687
688  failed:
689         CWARN("%s: failed to set nosquash_nids to \"%s\", %s: rc %d\n",
690               obd->obd_name, kernbuf, errmsg, rc);
691         if (kernbuf)
692                 OBD_FREE(kernbuf, count + 1);
693         RETURN(rc);
694 }
695
696 static int lprocfs_rd_mdt_som(char *page, char **start, off_t off,
697                               int count, int *eof, void *data)
698 {
699         struct obd_device *obd = data;
700         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
701
702         return snprintf(page, count, "%sabled\n",
703                         mdt->mdt_som_conf ? "en" : "dis");
704 }
705
706 static int lprocfs_wr_mdt_som(struct file *file, const char *buffer,
707                               unsigned long count, void *data)
708 {
709         struct obd_export *exp;
710         struct obd_device *obd = data;
711         struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
712         char kernbuf[16];
713         unsigned long val = 0;
714
715         if (count > (sizeof(kernbuf) - 1))
716                 return -EINVAL;
717
718         if (cfs_copy_from_user(kernbuf, buffer, count))
719                 return -EFAULT;
720
721         kernbuf[count] = '\0';
722
723         if (!strcmp(kernbuf, "enabled"))
724                 val = 1;
725         else if (strcmp(kernbuf, "disabled"))
726                 return -EINVAL;
727
728         if (mdt->mdt_som_conf == val)
729                 return count;
730
731         if (!obd->obd_process_conf) {
732                 CERROR("Temporary SOM change is not supported, use lctl "
733                        "conf_param for permanent setting\n");
734                 return count;
735         }
736
737         /* 1 stands for self export. */
738         cfs_list_for_each_entry(exp, &obd->obd_exports, exp_obd_chain) {
739                 if (exp == obd->obd_self_export)
740                         continue;
741                 if (exp->exp_connect_flags & OBD_CONNECT_MDS_MDS)
742                         continue;
743                 /* Some clients are already connected, skip the change */
744                 LCONSOLE_INFO("%s is already connected, SOM will be %s on "
745                               "the next mount\n", exp->exp_client_uuid.uuid,
746                               val ? "enabled" : "disabled");
747                 return count;
748         }
749
750         mdt->mdt_som_conf = val;
751         LCONSOLE_INFO("Enabling SOM\n");
752
753         return count;
754 }
755
756 /* Temporary; for testing purposes only */
757 static int lprocfs_mdt_wr_mdc(struct file *file, const char *buffer,
758                               unsigned long count, void *data)
759 {
760         struct obd_device *obd = data;
761         struct obd_export *exp = NULL;
762         struct obd_uuid uuid;
763         char tmpbuf[sizeof(struct obd_uuid)];
764
765         sscanf(buffer, "%40s", tmpbuf);
766
767         obd_str2uuid(&uuid, tmpbuf);
768         exp = cfs_hash_lookup(obd->obd_uuid_hash, &uuid);
769         if (exp == NULL) {
770                 CERROR("%s: no export %s found\n",
771                        obd->obd_name, obd_uuid2str(&uuid));
772         } else {
773                 mdt_hsm_copytool_send(exp);
774                 class_export_put(exp);
775         }
776
777         return count;
778 }
779
780 static struct lprocfs_vars lprocfs_mdt_obd_vars[] = {
781         { "uuid",                       lprocfs_rd_uuid,                 0, 0 },
782         { "recovery_status",            lprocfs_obd_rd_recovery_status,  0, 0 },
783         { "num_exports",                lprocfs_rd_num_exports,          0, 0 },
784         { "identity_expire",            lprocfs_rd_identity_expire,
785                                         lprocfs_wr_identity_expire,         0 },
786         { "identity_acquire_expire",    lprocfs_rd_identity_acquire_expire,
787                                         lprocfs_wr_identity_acquire_expire, 0 },
788         { "identity_upcall",            lprocfs_rd_identity_upcall,
789                                         lprocfs_wr_identity_upcall,         0 },
790         { "identity_flush",             0, lprocfs_wr_identity_flush,       0 },
791         { "identity_info",              0, lprocfs_wr_identity_info,        0 },
792         { "capa",                       lprocfs_rd_capa,
793                                         lprocfs_wr_capa,                    0 },
794         { "capa_timeout",               lprocfs_rd_capa_timeout,
795                                         lprocfs_wr_capa_timeout,            0 },
796         { "capa_key_timeout",           lprocfs_rd_ck_timeout,
797                                         lprocfs_wr_ck_timeout,              0 },
798         { "capa_count",                 lprocfs_rd_capa_count,           0, 0 },
799         { "site_stats",                 lprocfs_rd_site_stats,           0, 0 },
800         { "evict_client",               0, lprocfs_mdt_wr_evict_client,     0 },
801         { "hash_stats",                 lprocfs_obd_rd_hash,    0, 0 },
802         { "sec_level",                  lprocfs_rd_sec_level,
803                                         lprocfs_wr_sec_level,               0 },
804         { "commit_on_sharing",          lprocfs_rd_cos, lprocfs_wr_cos, 0 },
805         { "root_squash",                lprocfs_rd_root_squash,
806                                         lprocfs_wr_root_squash,             0 },
807         { "nosquash_nids",              lprocfs_rd_nosquash_nids,
808                                         lprocfs_wr_nosquash_nids,           0 },
809         { "som",                        lprocfs_rd_mdt_som,
810                                         lprocfs_wr_mdt_som, 0 },
811         { "mdccomm",                    0, lprocfs_mdt_wr_mdc,              0 },
812         { "instance",                   lprocfs_target_rd_instance,         0 },
813         { "ir_factor",                  lprocfs_obd_rd_ir_factor,
814                                         lprocfs_obd_wr_ir_factor,           0 },
815         { 0 }
816 };
817
818 static struct lprocfs_vars lprocfs_mdt_module_vars[] = {
819         { "num_refs",                   lprocfs_rd_numrefs,              0, 0 },
820         { 0 }
821 };
822
823 void lprocfs_mdt_init_vars(struct lprocfs_static_vars *lvars)
824 {
825     lvars->module_vars  = lprocfs_mdt_module_vars;
826     lvars->obd_vars     = lprocfs_mdt_obd_vars;
827 }
828
829 void mdt_counter_incr(struct obd_export *exp, int opcode)
830 {
831         if (exp->exp_obd && exp->exp_obd->md_stats)
832                 lprocfs_counter_incr(exp->exp_obd->md_stats, opcode);
833         if (exp->exp_nid_stats && exp->exp_nid_stats->nid_stats != NULL)
834                 lprocfs_counter_incr(exp->exp_nid_stats->nid_stats, opcode);
835
836 }
837
838 void mdt_stats_counter_init(struct lprocfs_stats *stats)
839 {
840         lprocfs_counter_init(stats, LPROC_MDT_OPEN, 0, "open", "reqs");
841         lprocfs_counter_init(stats, LPROC_MDT_CLOSE, 0, "close", "reqs");
842         lprocfs_counter_init(stats, LPROC_MDT_MKNOD, 0, "mknod", "reqs");
843         lprocfs_counter_init(stats, LPROC_MDT_LINK, 0, "link", "reqs");
844         lprocfs_counter_init(stats, LPROC_MDT_UNLINK, 0, "unlink", "reqs");
845         lprocfs_counter_init(stats, LPROC_MDT_MKDIR, 0, "mkdir", "reqs");
846         lprocfs_counter_init(stats, LPROC_MDT_RMDIR, 0, "rmdir", "reqs");
847         lprocfs_counter_init(stats, LPROC_MDT_RENAME, 0, "rename", "reqs");
848         lprocfs_counter_init(stats, LPROC_MDT_GETATTR, 0, "getattr", "reqs");
849         lprocfs_counter_init(stats, LPROC_MDT_SETATTR, 0, "setattr", "reqs");
850         lprocfs_counter_init(stats, LPROC_MDT_GETXATTR, 0, "getxattr", "reqs");
851         lprocfs_counter_init(stats, LPROC_MDT_SETXATTR, 0, "setxattr", "reqs");
852         lprocfs_counter_init(stats, LPROC_MDT_STATFS, 0, "statfs", "reqs");
853         lprocfs_counter_init(stats, LPROC_MDT_SYNC, 0, "sync", "reqs");
854 }