Whamcloud - gitweb
LU-14194 cksum: add lprocfs checksum support in MDC/MDT
[fs/lustre-release.git] / lustre / mdc / lproc_mdc.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  */
32 #define DEBUG_SUBSYSTEM S_CLASS
33
34 #include <linux/vfs.h>
35 #include <obd_class.h>
36 #include <obd_cksum.h>
37 #include <lprocfs_status.h>
38 #include <lustre_osc.h>
39 #include <cl_object.h>
40 #include "mdc_internal.h"
41
42 static ssize_t active_show(struct kobject *kobj, struct attribute *attr,
43                            char *buf)
44 {
45         struct obd_device *obd = container_of(kobj, struct obd_device,
46                                               obd_kset.kobj);
47         struct obd_import *imp;
48         ssize_t len;
49
50         with_imp_locked(obd, imp, len)
51                 len = sprintf(buf, "%d\n", !imp->imp_deactive);
52         return len;
53 }
54
55 static ssize_t active_store(struct kobject *kobj, struct attribute *attr,
56                             const char *buffer, size_t count)
57 {
58         struct obd_device *obd = container_of(kobj, struct obd_device,
59                                               obd_kset.kobj);
60         bool val;
61         int rc;
62
63         rc = kstrtobool(buffer, &val);
64         if (rc)
65                 return rc;
66
67         /* opposite senses */
68         if (obd->u.cli.cl_import->imp_deactive == val)
69                 rc = ptlrpc_set_import_active(obd->u.cli.cl_import, val);
70         else
71                 CDEBUG(D_CONFIG, "activate %u: ignoring repeat request\n",
72                        val);
73
74         return count;
75 }
76 LUSTRE_RW_ATTR(active);
77
78 static ssize_t max_rpcs_in_flight_show(struct kobject *kobj,
79                                        struct attribute *attr,
80                                        char *buf)
81 {
82         struct obd_device *obd = container_of(kobj, struct obd_device,
83                                               obd_kset.kobj);
84         ssize_t len;
85         u32 max;
86
87         max = obd_get_max_rpcs_in_flight(&obd->u.cli);
88         len = sprintf(buf, "%u\n", max);
89
90         return len;
91 }
92
93 static ssize_t max_rpcs_in_flight_store(struct kobject *kobj,
94                                         struct attribute *attr,
95                                         const char *buffer,
96                                         size_t count)
97 {
98         struct obd_device *obd = container_of(kobj, struct obd_device,
99                                               obd_kset.kobj);
100         unsigned int val;
101         int rc;
102
103         rc = kstrtouint(buffer, 10, &val);
104         if (rc)
105                 return rc;
106
107         rc = obd_set_max_rpcs_in_flight(&obd->u.cli, val);
108         if (rc)
109                 count = rc;
110
111         return count;
112 }
113 LUSTRE_RW_ATTR(max_rpcs_in_flight);
114
115 static ssize_t max_mod_rpcs_in_flight_show(struct kobject *kobj,
116                                            struct attribute *attr,
117                                            char *buf)
118 {
119         struct obd_device *obd = container_of(kobj, struct obd_device,
120                                               obd_kset.kobj);
121         u16 max;
122
123         max = obd_get_max_mod_rpcs_in_flight(&obd->u.cli);
124         return sprintf(buf, "%hu\n", max);
125 }
126
127 static ssize_t max_mod_rpcs_in_flight_store(struct kobject *kobj,
128                                             struct attribute *attr,
129                                             const char *buffer,
130                                             size_t count)
131 {
132         struct obd_device *obd = container_of(kobj, struct obd_device,
133                                               obd_kset.kobj);
134         u16 val;
135         int rc;
136
137         rc = kstrtou16(buffer, 10, &val);
138         if (rc)
139                 return rc;
140
141         rc = obd_set_max_mod_rpcs_in_flight(&obd->u.cli, val);
142         if (rc)
143                 count = rc;
144
145         return count;
146 }
147 LUSTRE_RW_ATTR(max_mod_rpcs_in_flight);
148
149 static int mdc_max_dirty_mb_seq_show(struct seq_file *m, void *v)
150 {
151         struct obd_device *obd = m->private;
152         struct client_obd *cli = &obd->u.cli;
153
154         seq_printf(m, "%lu\n", PAGES_TO_MiB(cli->cl_dirty_max_pages));
155         return 0;
156 }
157
158 static ssize_t mdc_max_dirty_mb_seq_write(struct file *file,
159                                           const char __user *buffer,
160                                           size_t count, loff_t *off)
161 {
162         struct seq_file *sfl = file->private_data;
163         struct obd_device *obd = sfl->private;
164         struct client_obd *cli = &obd->u.cli;
165         char kernbuf[22] = "";
166         u64 pages_number;
167         int rc;
168
169         if (count >= sizeof(kernbuf))
170                 return -EINVAL;
171
172         if (copy_from_user(kernbuf, buffer, count))
173                 return -EFAULT;
174         kernbuf[count] = 0;
175
176         rc = sysfs_memparse(kernbuf, count, &pages_number, "MiB");
177         if (rc < 0)
178                 return rc;
179
180         /* MB -> pages */
181         pages_number = round_up(pages_number, 1024 * 1024) >> PAGE_SHIFT;
182         if (pages_number <= 0 ||
183             pages_number >= MiB_TO_PAGES(OSC_MAX_DIRTY_MB_MAX) ||
184             pages_number > cfs_totalram_pages() / 4) /* 1/4 of RAM */
185                 return -ERANGE;
186
187         spin_lock(&cli->cl_loi_list_lock);
188         cli->cl_dirty_max_pages = pages_number;
189         osc_wake_cache_waiters(cli);
190         spin_unlock(&cli->cl_loi_list_lock);
191
192         return count;
193 }
194 LPROC_SEQ_FOPS(mdc_max_dirty_mb);
195
196 DECLARE_CKSUM_NAME;
197
198 static int mdc_checksum_type_seq_show(struct seq_file *m, void *v)
199 {
200         struct obd_device *obd = m->private;
201         int i;
202
203         if (obd == NULL)
204                 return 0;
205
206         for (i = 0; i < ARRAY_SIZE(cksum_name); i++) {
207                 if ((BIT(i) & obd->u.cli.cl_supp_cksum_types) == 0)
208                         continue;
209                 if (obd->u.cli.cl_cksum_type == BIT(i))
210                         seq_printf(m, "[%s] ", cksum_name[i]);
211                 else
212                         seq_printf(m, "%s ", cksum_name[i]);
213         }
214         seq_puts(m, "\n");
215
216         return 0;
217 }
218
219 static ssize_t mdc_checksum_type_seq_write(struct file *file,
220                                            const char __user *buffer,
221                                            size_t count, loff_t *off)
222 {
223         struct seq_file *m = file->private_data;
224         struct obd_device *obd = m->private;
225         char kernbuf[10];
226         int rc = -EINVAL;
227         int i;
228
229         if (obd == NULL)
230                 return 0;
231
232         if (count > sizeof(kernbuf) - 1)
233                 return -EINVAL;
234         if (copy_from_user(kernbuf, buffer, count))
235                 return -EFAULT;
236
237         if (count > 0 && kernbuf[count - 1] == '\n')
238                 kernbuf[count - 1] = '\0';
239         else
240                 kernbuf[count] = '\0';
241
242         for (i = 0; i < ARRAY_SIZE(cksum_name); i++) {
243                 if (strcmp(kernbuf, cksum_name[i]) == 0) {
244                         obd->u.cli.cl_preferred_cksum_type = BIT(i);
245                         if (obd->u.cli.cl_supp_cksum_types & BIT(i)) {
246                                 obd->u.cli.cl_cksum_type = BIT(i);
247                                 rc = count;
248                         } else {
249                                 rc = -ENOTSUPP;
250                         }
251                         break;
252                 }
253         }
254
255         return rc;
256 }
257 LPROC_SEQ_FOPS(mdc_checksum_type);
258
259 static ssize_t checksums_show(struct kobject *kobj,
260                               struct attribute *attr, char *buf)
261 {
262         struct obd_device *obd = container_of(kobj, struct obd_device,
263                                               obd_kset.kobj);
264
265         return scnprintf(buf, PAGE_SIZE, "%d\n", !!obd->u.cli.cl_checksum);
266 }
267
268 static ssize_t checksums_store(struct kobject *kobj,
269                                struct attribute *attr,
270                                const char *buffer,
271                                size_t count)
272 {
273         struct obd_device *obd = container_of(kobj, struct obd_device,
274                                               obd_kset.kobj);
275         bool val;
276         int rc;
277
278         rc = kstrtobool(buffer, &val);
279         if (rc)
280                 return rc;
281
282         obd->u.cli.cl_checksum = val;
283
284         return count;
285 }
286 LUSTRE_RW_ATTR(checksums);
287
288 static ssize_t checksum_dump_show(struct kobject *kobj,
289                                   struct attribute *attr, char *buf)
290 {
291         struct obd_device *obd = container_of(kobj, struct obd_device,
292                                               obd_kset.kobj);
293
294         return scnprintf(buf, PAGE_SIZE, "%d\n", !!obd->u.cli.cl_checksum_dump);
295 }
296
297 static ssize_t checksum_dump_store(struct kobject *kobj,
298                                    struct attribute *attr,
299                                    const char *buffer,
300                                    size_t count)
301 {
302         struct obd_device *obd = container_of(kobj, struct obd_device,
303                                               obd_kset.kobj);
304         bool val;
305         int rc;
306
307         rc = kstrtobool(buffer, &val);
308         if (rc)
309                 return rc;
310
311         obd->u.cli.cl_checksum_dump = val;
312
313         return count;
314 }
315 LUSTRE_RW_ATTR(checksum_dump);
316
317 static ssize_t contention_seconds_show(struct kobject *kobj,
318                                        struct attribute *attr,
319                                        char *buf)
320 {
321         struct obd_device *obd = container_of(kobj, struct obd_device,
322                                               obd_kset.kobj);
323         struct osc_device *od = obd2osc_dev(obd);
324
325         return sprintf(buf, "%lld\n", od->od_contention_time);
326 }
327
328 static ssize_t contention_seconds_store(struct kobject *kobj,
329                                         struct attribute *attr,
330                                         const char *buffer,
331                                         size_t count)
332 {
333         struct obd_device *obd = container_of(kobj, struct obd_device,
334                                               obd_kset.kobj);
335         struct osc_device *od = obd2osc_dev(obd);
336         time64_t val;
337         int rc;
338
339         rc = kstrtoll(buffer, 0, &val);
340         if (rc)
341                 return rc;
342
343         od->od_contention_time = val;
344
345         return count;
346 }
347 LUSTRE_RW_ATTR(contention_seconds);
348
349 LUSTRE_ATTR(mds_conn_uuid, 0444, conn_uuid_show, NULL);
350 LUSTRE_RO_ATTR(conn_uuid);
351
352 LUSTRE_RW_ATTR(ping);
353
354 static int mdc_cached_mb_seq_show(struct seq_file *m, void *v)
355 {
356         struct obd_device *obd = m->private;
357         struct client_obd *cli = &obd->u.cli;
358         int shift = 20 - PAGE_SHIFT;
359
360         seq_printf(m, "used_mb: %ld\n"
361                    "busy_cnt: %ld\n"
362                    "reclaim: %llu\n",
363                    (atomic_long_read(&cli->cl_lru_in_list) +
364                     atomic_long_read(&cli->cl_lru_busy)) >> shift,
365                     atomic_long_read(&cli->cl_lru_busy),
366                    cli->cl_lru_reclaim);
367
368         return 0;
369 }
370
371 /* shrink the number of caching pages to a specific number */
372 static ssize_t
373 mdc_cached_mb_seq_write(struct file *file, const char __user *buffer,
374                         size_t count, loff_t *off)
375 {
376         struct seq_file *sfl = file->private_data;
377         struct obd_device *obd = sfl->private;
378         struct client_obd *cli = &obd->u.cli;
379         u64 pages_number;
380         const char *tmp;
381         long rc;
382         char kernbuf[128];
383
384         if (count >= sizeof(kernbuf))
385                 return -EINVAL;
386
387         if (copy_from_user(kernbuf, buffer, count))
388                 return -EFAULT;
389         kernbuf[count] = 0;
390
391         tmp = lprocfs_find_named_value(kernbuf, "used_mb:", &count);
392         rc = sysfs_memparse(tmp, count, &pages_number, "MiB");
393         if (rc < 0)
394                 return rc;
395
396         pages_number >>= PAGE_SHIFT;
397
398         rc = atomic_long_read(&cli->cl_lru_in_list) - pages_number;
399         if (rc > 0) {
400                 struct lu_env *env;
401                 __u16 refcheck;
402
403                 env = cl_env_get(&refcheck);
404                 if (!IS_ERR(env)) {
405                         (void)osc_lru_shrink(env, cli, rc, true);
406                         cl_env_put(env, &refcheck);
407                 }
408         }
409
410         return count;
411 }
412 LPROC_SEQ_FOPS(mdc_cached_mb);
413
414 static int mdc_unstable_stats_seq_show(struct seq_file *m, void *v)
415 {
416         struct obd_device *obd = m->private;
417         struct client_obd *cli = &obd->u.cli;
418         long pages;
419         int mb;
420
421         pages = atomic_long_read(&cli->cl_unstable_count);
422         mb    = (pages * PAGE_SIZE) >> 20;
423
424         seq_printf(m, "unstable_pages: %20ld\n"
425                    "unstable_mb:              %10d\n", pages, mb);
426         return 0;
427 }
428 LPROC_SEQ_FOPS_RO(mdc_unstable_stats);
429
430 static ssize_t mdc_rpc_stats_seq_write(struct file *file,
431                                        const char __user *buf,
432                                        size_t len, loff_t *off)
433 {
434         struct seq_file *seq = file->private_data;
435         struct obd_device *obd = seq->private;
436         struct client_obd *cli = &obd->u.cli;
437
438         lprocfs_oh_clear(&cli->cl_mod_rpcs_hist);
439
440         lprocfs_oh_clear(&cli->cl_read_rpc_hist);
441         lprocfs_oh_clear(&cli->cl_write_rpc_hist);
442         lprocfs_oh_clear(&cli->cl_read_page_hist);
443         lprocfs_oh_clear(&cli->cl_write_page_hist);
444         lprocfs_oh_clear(&cli->cl_read_offset_hist);
445         lprocfs_oh_clear(&cli->cl_write_offset_hist);
446
447         return len;
448 }
449
450 static int mdc_rpc_stats_seq_show(struct seq_file *seq, void *v)
451 {
452         struct obd_device *obd = seq->private;
453         struct client_obd *cli = &obd->u.cli;
454         unsigned long read_tot = 0, write_tot = 0, read_cum, write_cum;
455         int i;
456
457         obd_mod_rpc_stats_seq_show(cli, seq);
458
459         spin_lock(&cli->cl_loi_list_lock);
460
461         seq_printf(seq, "\nread RPCs in flight:  %d\n",
462                    cli->cl_r_in_flight);
463         seq_printf(seq, "write RPCs in flight: %d\n",
464                    cli->cl_w_in_flight);
465         seq_printf(seq, "pending write pages:  %d\n",
466                    atomic_read(&cli->cl_pending_w_pages));
467         seq_printf(seq, "pending read pages:   %d\n",
468                    atomic_read(&cli->cl_pending_r_pages));
469
470         seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
471         seq_printf(seq, "pages per rpc         rpcs   %% cum %% |");
472         seq_printf(seq, "       rpcs   %% cum %%\n");
473
474         read_tot = lprocfs_oh_sum(&cli->cl_read_page_hist);
475         write_tot = lprocfs_oh_sum(&cli->cl_write_page_hist);
476
477         read_cum = 0;
478         write_cum = 0;
479         for (i = 0; i < OBD_HIST_MAX; i++) {
480                 unsigned long r = cli->cl_read_page_hist.oh_buckets[i];
481                 unsigned long w = cli->cl_write_page_hist.oh_buckets[i];
482
483                 read_cum += r;
484                 write_cum += w;
485                 seq_printf(seq, "%d:\t\t%10lu %3u %3u   | %10lu %3u %3u\n",
486                            1 << i, r, pct(r, read_tot),
487                            pct(read_cum, read_tot), w,
488                            pct(w, write_tot),
489                            pct(write_cum, write_tot));
490                 if (read_cum == read_tot && write_cum == write_tot)
491                         break;
492         }
493
494         seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
495         seq_printf(seq, "rpcs in flight        rpcs   %% cum %% |");
496         seq_printf(seq, "       rpcs   %% cum %%\n");
497
498         read_tot = lprocfs_oh_sum(&cli->cl_read_rpc_hist);
499         write_tot = lprocfs_oh_sum(&cli->cl_write_rpc_hist);
500
501         read_cum = 0;
502         write_cum = 0;
503         for (i = 1; i < OBD_HIST_MAX; i++) {
504                 unsigned long r = cli->cl_read_rpc_hist.oh_buckets[i];
505                 unsigned long w = cli->cl_write_rpc_hist.oh_buckets[i];
506
507                 read_cum += r;
508                 write_cum += w;
509                 seq_printf(seq, "%d:\t\t%10lu %3u %3u   | %10lu %3u %3u\n",
510                            i, r, pct(r, read_tot), pct(read_cum, read_tot), w,
511                            pct(w, write_tot), pct(write_cum, write_tot));
512                 if (read_cum == read_tot && write_cum == write_tot)
513                         break;
514         }
515
516         seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
517         seq_printf(seq, "offset                rpcs   %% cum %% |");
518         seq_printf(seq, "       rpcs   %% cum %%\n");
519
520         read_tot = lprocfs_oh_sum(&cli->cl_read_offset_hist);
521         write_tot = lprocfs_oh_sum(&cli->cl_write_offset_hist);
522
523         read_cum = 0;
524         write_cum = 0;
525         for (i = 0; i < OBD_HIST_MAX; i++) {
526                 unsigned long r = cli->cl_read_offset_hist.oh_buckets[i];
527                 unsigned long w = cli->cl_write_offset_hist.oh_buckets[i];
528
529                 read_cum += r;
530                 write_cum += w;
531                 seq_printf(seq, "%d:\t\t%10lu %3u %3u   | %10lu %3u %3u\n",
532                            (i == 0) ? 0 : 1 << (i - 1),
533                            r, pct(r, read_tot), pct(read_cum, read_tot),
534                            w, pct(w, write_tot), pct(write_cum, write_tot));
535                 if (read_cum == read_tot && write_cum == write_tot)
536                         break;
537         }
538         spin_unlock(&cli->cl_loi_list_lock);
539
540         return 0;
541 }
542 LPROC_SEQ_FOPS(mdc_rpc_stats);
543
544 static int mdc_stats_seq_show(struct seq_file *seq, void *v)
545 {
546         struct timespec64 now;
547         struct obd_device *obd = seq->private;
548         struct osc_stats *stats = &obd2osc_dev(obd)->od_stats;
549
550         ktime_get_real_ts64(&now);
551
552         seq_printf(seq, "snapshot_time:         %lld.%09lu (secs.nsecs)\n",
553                    (s64)now.tv_sec, now.tv_nsec);
554         seq_printf(seq, "lockless_write_bytes\t\t%llu\n",
555                    stats->os_lockless_writes);
556         seq_printf(seq, "lockless_read_bytes\t\t%llu\n",
557                    stats->os_lockless_reads);
558         seq_printf(seq, "lockless_truncate\t\t%llu\n",
559                    stats->os_lockless_truncates);
560         return 0;
561 }
562
563 static ssize_t mdc_stats_seq_write(struct file *file,
564                                    const char __user *buf,
565                                    size_t len, loff_t *off)
566 {
567         struct seq_file *seq = file->private_data;
568         struct obd_device *obd = seq->private;
569         struct osc_stats *stats = &obd2osc_dev(obd)->od_stats;
570
571         memset(stats, 0, sizeof(*stats));
572         return len;
573 }
574 LPROC_SEQ_FOPS(mdc_stats);
575
576 static int mdc_dom_min_repsize_seq_show(struct seq_file *m, void *v)
577 {
578         struct obd_device *obd = m->private;
579
580         seq_printf(m, "%u\n", obd->u.cli.cl_dom_min_inline_repsize);
581
582         return 0;
583 }
584
585 static ssize_t mdc_dom_min_repsize_seq_write(struct file *file,
586                                              const char __user *buffer,
587                                              size_t count, loff_t *off)
588 {
589         struct seq_file *m = file->private_data;
590         struct obd_device *obd = m->private;
591         unsigned int val;
592         int rc;
593
594         rc = kstrtouint_from_user(buffer, count, 0, &val);
595         if (rc)
596                 return rc;
597
598         if (val > MDC_DOM_MAX_INLINE_REPSIZE)
599                 return -ERANGE;
600
601         obd->u.cli.cl_dom_min_inline_repsize = val;
602         return count;
603 }
604 LPROC_SEQ_FOPS(mdc_dom_min_repsize);
605
606 LPROC_SEQ_FOPS_RO_TYPE(mdc, connect_flags);
607 LPROC_SEQ_FOPS_RO_TYPE(mdc, server_uuid);
608 LPROC_SEQ_FOPS_RO_TYPE(mdc, timeouts);
609 LPROC_SEQ_FOPS_RO_TYPE(mdc, state);
610 LPROC_SEQ_FOPS_RW_TYPE(mdc, obd_max_pages_per_rpc);
611 LPROC_SEQ_FOPS_RW_TYPE(mdc, import);
612 LPROC_SEQ_FOPS_RW_TYPE(mdc, pinger_recov);
613
614 struct lprocfs_vars lprocfs_mdc_obd_vars[] = {
615         { .name =       "connect_flags",
616           .fops =       &mdc_connect_flags_fops },
617         { .name =       "mds_server_uuid",
618           .fops =       &mdc_server_uuid_fops   },
619         { .name =       "max_pages_per_rpc",
620           .fops =       &mdc_obd_max_pages_per_rpc_fops },
621         { .name =       "max_dirty_mb",
622           .fops =       &mdc_max_dirty_mb_fops          },
623         { .name =       "mdc_cached_mb",
624           .fops =       &mdc_cached_mb_fops             },
625         { .name =       "checksum_type",
626           .fops =       &mdc_checksum_type_fops         },
627         { .name =       "timeouts",
628           .fops =       &mdc_timeouts_fops              },
629         { .name =       "import",
630           .fops =       &mdc_import_fops                },
631         { .name =       "state",
632           .fops =       &mdc_state_fops                 },
633         { .name =       "pinger_recov",
634           .fops =       &mdc_pinger_recov_fops          },
635         { .name =       "rpc_stats",
636           .fops =       &mdc_rpc_stats_fops             },
637         { .name =       "unstable_stats",
638           .fops =       &mdc_unstable_stats_fops        },
639         { .name =       "mdc_stats",
640           .fops =       &mdc_stats_fops                 },
641         { .name =       "mdc_dom_min_repsize",
642           .fops =       &mdc_dom_min_repsize_fops       },
643         { NULL }
644 };
645
646 static struct attribute *mdc_attrs[] = {
647         &lustre_attr_active.attr,
648         &lustre_attr_checksums.attr,
649         &lustre_attr_checksum_dump.attr,
650         &lustre_attr_max_rpcs_in_flight.attr,
651         &lustre_attr_max_mod_rpcs_in_flight.attr,
652         &lustre_attr_contention_seconds.attr,
653         &lustre_attr_mds_conn_uuid.attr,
654         &lustre_attr_conn_uuid.attr,
655         &lustre_attr_ping.attr,
656         NULL,
657 };
658
659 int mdc_tunables_init(struct obd_device *obd)
660 {
661         int rc;
662
663         obd->obd_ktype.default_attrs = mdc_attrs;
664         obd->obd_vars = lprocfs_mdc_obd_vars;
665
666         rc = lprocfs_obd_setup(obd, false);
667         if (rc)
668                 goto out_failed;
669 #ifdef CONFIG_PROC_FS
670         rc = lprocfs_alloc_md_stats(obd, 0);
671         if (rc) {
672                 lprocfs_obd_cleanup(obd);
673                 goto out_failed;
674         }
675 #endif
676         rc = sptlrpc_lprocfs_cliobd_attach(obd);
677         if (rc) {
678 #ifdef CONFIG_PROC_FS
679                 lprocfs_free_md_stats(obd);
680 #endif
681                 lprocfs_obd_cleanup(obd);
682                 goto out_failed;
683         }
684         ptlrpc_lprocfs_register_obd(obd);
685
686 out_failed:
687         return rc;
688 }