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