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