Whamcloud - gitweb
LU-17744 ldiskfs: mballoc stats fixes
[fs/lustre-release.git] / lustre / obdclass / obd_sysfs.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) 2007, 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  *
31  * lustre/obdclass/obd_sysfs.c
32  *
33  * Object Devices Class Driver
34  * These are the only exported functions, they provide some generic
35  * infrastructure for managing object devices
36  */
37
38 #define DEBUG_SUBSYSTEM S_CLASS
39
40 #include <linux/module.h>
41 #include <linux/errno.h>
42 #include <linux/kernel.h>
43 #include <linux/sched.h>
44 #include <linux/lp.h>
45 #include <linux/slab.h>
46 #include <linux/ioport.h>
47 #include <linux/fcntl.h>
48 #include <linux/delay.h>
49 #include <linux/skbuff.h>
50 #include <linux/proc_fs.h>
51 #include <linux/fs.h>
52 #include <linux/poll.h>
53 #include <linux/init.h>
54 #include <linux/list.h>
55 #include <linux/highmem.h>
56 #include <asm/io.h>
57 #include <asm/ioctls.h>
58 #include <asm/poll.h>
59 #include <asm/uaccess.h>
60 #include <linux/miscdevice.h>
61 #include <linux/seq_file.h>
62 #include <linux/kobject.h>
63
64 #include <libcfs/libcfs.h>
65 #include <libcfs/libcfs_crypto.h>
66 #include <obd_support.h>
67 #include <obd_class.h>
68 #include <lprocfs_status.h>
69 #include <uapi/linux/lnet/lnetctl.h>
70 #include <uapi/linux/lustre/lustre_ioctl.h>
71 #include <uapi/linux/lustre/lustre_ver.h>
72
73 bool obd_enable_health_write;
74 EXPORT_SYMBOL(obd_enable_health_write);
75
76 struct static_lustre_uintvalue_attr {
77         struct {
78                 struct attribute attr;
79                 ssize_t (*show)(struct kobject *kobj, struct attribute *attr,
80                                 char *buf);
81                 ssize_t (*store)(struct kobject *kobj, struct attribute *attr,
82                                  const char *buf, size_t len);
83         } u;
84         int *value;
85 };
86
87 static ssize_t static_uintvalue_show(struct kobject *kobj,
88                                      struct attribute *attr,
89                                      char *buf)
90 {
91         struct static_lustre_uintvalue_attr *lattr = (void *)attr;
92
93         return sprintf(buf, "%d\n", *lattr->value);
94 }
95
96 static ssize_t static_uintvalue_store(struct kobject *kobj,
97                                       struct attribute *attr,
98                                       const char *buffer, size_t count)
99 {
100         struct static_lustre_uintvalue_attr *lattr = (void *)attr;
101         unsigned int val;
102         int rc;
103
104         rc = kstrtouint(buffer, 10, &val);
105         if (rc)
106                 return rc;
107
108         *lattr->value = val;
109
110         return count;
111 }
112
113 #define LUSTRE_STATIC_UINT_ATTR(name, value)                            \
114 static struct static_lustre_uintvalue_attr lustre_sattr_##name =        \
115         { __ATTR(name, 0644, static_uintvalue_show,                     \
116                  static_uintvalue_store), value }
117
118 LUSTRE_STATIC_UINT_ATTR(debug_peer_on_timeout, &obd_debug_peer_on_timeout);
119 LUSTRE_STATIC_UINT_ATTR(dump_on_timeout, &obd_dump_on_timeout);
120 LUSTRE_STATIC_UINT_ATTR(dump_on_eviction, &obd_dump_on_eviction);
121 LUSTRE_STATIC_UINT_ATTR(at_min, &at_min);
122 LUSTRE_STATIC_UINT_ATTR(at_max, &at_max);
123 LUSTRE_STATIC_UINT_ATTR(at_extra, &at_extra);
124 LUSTRE_STATIC_UINT_ATTR(at_early_margin, &at_early_margin);
125 LUSTRE_STATIC_UINT_ATTR(at_history, &at_history);
126 LUSTRE_STATIC_UINT_ATTR(enable_stats_header, &obd_enable_stats_header);
127 LUSTRE_STATIC_UINT_ATTR(lbug_on_eviction, &obd_lbug_on_eviction);
128 LUSTRE_STATIC_UINT_ATTR(ping_interval, &ping_interval);
129 LUSTRE_STATIC_UINT_ATTR(evict_multiplier, &ping_evict_timeout_multiplier);
130
131 #ifdef HAVE_SERVER_SUPPORT
132 LUSTRE_STATIC_UINT_ATTR(ldlm_timeout, &ldlm_timeout);
133 LUSTRE_STATIC_UINT_ATTR(bulk_timeout, &bulk_timeout);
134 #endif
135
136 static ssize_t memused_show(struct kobject *kobj, struct attribute *attr,
137                             char *buf)
138 {
139         return sprintf(buf, "%llu\n", obd_memory_sum());
140 }
141 LUSTRE_RO_ATTR(memused);
142
143 static ssize_t memused_max_show(struct kobject *kobj, struct attribute *attr,
144                                 char *buf)
145 {
146         return sprintf(buf, "%llu\n", obd_memory_max());
147 }
148 LUSTRE_RO_ATTR(memused_max);
149
150 static ssize_t max_dirty_mb_show(struct kobject *kobj, struct attribute *attr,
151                                  char *buf)
152 {
153         return sprintf(buf, "%lu\n",
154                        obd_max_dirty_pages / (1 << (20 - PAGE_SHIFT)));
155 }
156
157 static ssize_t max_dirty_mb_store(struct kobject *kobj, struct attribute *attr,
158                                   const char *buffer, size_t count)
159 {
160         unsigned long val;
161         int rc;
162
163         rc = kstrtoul(buffer, 10, &val);
164         if (rc)
165                 return rc;
166
167         val *= 1 << (20 - PAGE_SHIFT); /* convert to pages */
168
169         if (val > ((cfs_totalram_pages() / 10) * 9)) {
170                 /* Somebody wants to assign too much memory to dirty pages */
171                 return -EINVAL;
172         }
173
174         if (val < 4 << (20 - PAGE_SHIFT)) {
175                 /* Less than 4 Mb for dirty cache is also bad */
176                 return -EINVAL;
177         }
178
179         obd_max_dirty_pages = val;
180
181         return count;
182 }
183 LUSTRE_RW_ATTR(max_dirty_mb);
184
185 #ifdef HAVE_SERVER_SUPPORT
186 static ssize_t no_transno_store(struct kobject *kobj,
187                                 struct attribute *attr,
188                                 const char *buffer, size_t count)
189 {
190         struct obd_device *obd;
191         unsigned int idx;
192         int rc;
193
194         rc = kstrtouint(buffer, 10, &idx);
195         if (rc)
196                 return rc;
197
198         obd = class_num2obd(idx);
199         if (!obd || !obd->obd_attached) {
200                 if (obd)
201                         CERROR("%s: not attached\n", obd->obd_name);
202                 return -ENODEV;
203         }
204
205         spin_lock(&obd->obd_dev_lock);
206         obd->obd_no_transno = 1;
207         spin_unlock(&obd->obd_dev_lock);
208         return count;
209 }
210 LUSTRE_WO_ATTR(no_transno);
211 #endif /* HAVE_SERVER_SUPPORT */
212
213 static ssize_t version_show(struct kobject *kobj, struct attribute *attr,
214                             char *buf)
215 {
216         return sprintf(buf, "%s\n", LUSTRE_VERSION_STRING);
217 }
218
219 static ssize_t pinger_show(struct kobject *kobj, struct attribute *attr,
220                            char *buf)
221 {
222 #ifdef CONFIG_LUSTRE_FS_PINGER
223         const char *state = "on";
224 #else
225         const char *state = "off";
226 #endif
227         return sprintf(buf, "%s\n", state);
228 }
229
230 /**
231  * Check all obd devices health
232  *
233  * \param kobj
234  * \param buf [in]
235  *
236  * \retval number of characters printed if healthy
237  */
238 static ssize_t
239 health_check_show(struct kobject *kobj, struct attribute *attr, char *buf)
240 {
241         struct obd_device *obd = NULL;
242         unsigned long dev_no = 0;
243         bool healthy = true;
244         size_t len = 0;
245
246         if (libcfs_catastrophe)
247                 return sprintf(buf, "LBUG\n");
248
249         obd_device_lock();
250         obd_device_for_each_cond(dev_no, obd, obd->obd_attached &&
251                                  obd->obd_set_up && !obd->obd_stopping &&
252                                  !obd->obd_read_only) {
253                 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
254
255                 class_incref(obd, __func__, current);
256                 obd_device_unlock();
257                 if (obd_health_check(NULL, obd))
258                         healthy = false;
259                 obd_device_lock();
260                 class_decref(obd, __func__, current);
261
262                 if (!healthy)
263                         break;
264         }
265         obd_device_unlock();
266
267         if (healthy)
268                 len = sprintf(buf, "healthy\n");
269         else
270                 len = sprintf(buf, "NOT HEALTHY\n");
271
272         return len;
273 }
274
275 #ifdef HAVE_SERVER_SUPPORT
276 static ssize_t enable_health_write_show(struct kobject *kobj,
277                                         struct attribute *attr,
278                                         char *buf)
279 {
280         return scnprintf(buf, PAGE_SIZE, "%u\n",
281                          obd_enable_health_write);
282 }
283
284 static ssize_t enable_health_write_store(struct kobject *kobj,
285                                          struct attribute *attr,
286                                          const char *buf, size_t count)
287 {
288         int rc = 0;
289
290         rc = kstrtobool(buf, &obd_enable_health_write);
291         if (rc)
292                 return rc;
293
294         return count;
295 }
296 LUSTRE_RW_ATTR(enable_health_write);
297 #endif /* HAVE_SERVER_SUPPORT */
298
299 static ssize_t jobid_var_show(struct kobject *kobj, struct attribute *attr,
300                               char *buf)
301 {
302         int rc = 0;
303
304         if (strlen(obd_jobid_var))
305                 rc = scnprintf(buf, PAGE_SIZE, "%s\n", obd_jobid_var);
306         return rc;
307 }
308
309 static ssize_t jobid_var_store(struct kobject *kobj, struct attribute *attr,
310                                const char *buffer, size_t count)
311 {
312         if (!count || count > JOBSTATS_JOBID_VAR_MAX_LEN)
313                 return -EINVAL;
314
315         memset(obd_jobid_var, 0, JOBSTATS_JOBID_VAR_MAX_LEN + 1);
316
317         memcpy(obd_jobid_var, buffer, count);
318
319         /* Trim the trailing '\n' if any */
320         if (obd_jobid_var[count - 1] == '\n')
321                 obd_jobid_var[count - 1] = 0;
322
323         return count;
324 }
325
326 static ssize_t jobid_name_show(struct kobject *kobj, struct attribute *attr,
327                                char *buf)
328 {
329         int rc = 0;
330
331         if (strlen(obd_jobid_name))
332                 rc = scnprintf(buf, PAGE_SIZE, "%s\n", obd_jobid_name);
333         return rc;
334 }
335
336 static ssize_t jobid_name_store(struct kobject *kobj, struct attribute *attr,
337                                 const char *buffer, size_t count)
338 {
339         if (!count || count > LUSTRE_JOBID_SIZE)
340                 return -EINVAL;
341
342         if (strcmp(obd_jobid_var, JOBSTATS_NODELOCAL) != 0 &&
343             !strchr(buffer, '%')) {
344                 lustre_jobid_clear(buffer);
345                 return count;
346         }
347
348         /* clear previous value */
349         memset(obd_jobid_name, 0, LUSTRE_JOBID_SIZE);
350
351         memcpy(obd_jobid_name, buffer, count);
352
353         /* Trim the trailing '\n' if any */
354         if (obd_jobid_name[count - 1] == '\n') {
355                 /* Don't echo just a newline */
356                 if (count == 1)
357                         return -EINVAL;
358                 obd_jobid_name[count - 1] = 0;
359         }
360
361         return count;
362 }
363
364 static ssize_t jobid_this_session_show(struct kobject *kobj,
365                                        struct attribute *attr,
366                                        char *buf)
367 {
368         char *jid;
369         int ret = -ENOENT;
370
371         rcu_read_lock();
372         jid = jobid_current();
373         if (jid)
374                 ret = scnprintf(buf, PAGE_SIZE, "%s\n", jid);
375         rcu_read_unlock();
376         return ret;
377 }
378
379 static ssize_t jobid_this_session_store(struct kobject *kobj,
380                                         struct attribute *attr,
381                                         const char *buffer,
382                                         size_t count)
383 {
384         char *jobid;
385         int len;
386         int ret;
387
388         if (!count || count > LUSTRE_JOBID_SIZE)
389                 return -EINVAL;
390
391         jobid = kstrndup(buffer, count, GFP_KERNEL);
392         if (!jobid)
393                 return -ENOMEM;
394         len = strcspn(jobid, "\n ");
395         jobid[len] = '\0';
396         ret = jobid_set_current(jobid);
397         kfree(jobid);
398
399         return ret ?: count;
400 }
401
402 static ssize_t timeout_show(struct kobject *kobj,
403                             struct attribute *attr,
404                             char *buf)
405 {
406         return sprintf(buf, "%u\n", obd_timeout);
407 }
408
409 static ssize_t timeout_store(struct kobject *kobj,
410                              struct attribute *attr,
411                              const char *buffer,
412                              size_t count)
413 {
414         unsigned int val;
415         int rc;
416
417         rc = kstrtouint(buffer, 10, &val);
418         if (rc)
419                 return rc;
420         obd_timeout = val ?: 1U;
421         ping_interval = max(obd_timeout / 4, 1U);
422
423         return count;
424 }
425
426 static ssize_t debug_raw_pointers_show(struct kobject *kobj,
427                                        struct attribute *attr,
428                                        char *buf)
429 {
430         return scnprintf(buf, PAGE_SIZE, "%d\n", get_debug_raw_pointers());
431 }
432
433 static ssize_t debug_raw_pointers_store(struct kobject *kobj,
434                              struct attribute *attr,
435                              const char *buffer,
436                              size_t count)
437 {
438         bool initial = get_debug_raw_pointers();
439         bool val;
440         int rc;
441
442         rc = kstrtobool(buffer, &val);
443         if (rc)
444                 return rc;
445
446         if ((initial && val) || (!initial && !val))
447                 return count;
448
449         if (val) {
450                 rc = debug_format_buffer_alloc_buffers();
451                 if (rc)
452                         return rc;
453         } else {
454                 debug_format_buffer_free_buffers();
455         }
456         set_debug_raw_pointers(val);
457
458         return count;
459 }
460
461 /* Root for /sys/kernel/debug/lustre */
462 struct dentry *debugfs_lustre_root;
463 EXPORT_SYMBOL_GPL(debugfs_lustre_root);
464
465 #ifdef CONFIG_PROC_FS
466 /* Root for /proc/fs/lustre */
467 struct proc_dir_entry *proc_lustre_root;
468 EXPORT_SYMBOL(proc_lustre_root);
469 #else
470 #define lprocfs_base NULL
471 #endif /* CONFIG_PROC_FS */
472
473 LUSTRE_RO_ATTR(version);
474 LUSTRE_RO_ATTR(pinger);
475 LUSTRE_RO_ATTR(health_check);
476 LUSTRE_RW_ATTR(jobid_var);
477 LUSTRE_RW_ATTR(jobid_name);
478 LUSTRE_RW_ATTR(jobid_this_session);
479 LUSTRE_RW_ATTR(timeout);
480 LUSTRE_RW_ATTR(debug_raw_pointers);
481
482 static struct attribute *lustre_attrs[] = {
483         &lustre_attr_version.attr,
484         &lustre_attr_pinger.attr,
485         &lustre_sattr_enable_stats_header.u.attr,
486         &lustre_attr_health_check.attr,
487         &lustre_attr_jobid_name.attr,
488         &lustre_attr_jobid_var.attr,
489         &lustre_attr_jobid_this_session.attr,
490         &lustre_attr_timeout.attr,
491         &lustre_attr_debug_raw_pointers.attr,
492         &lustre_attr_max_dirty_mb.attr,
493         &lustre_sattr_debug_peer_on_timeout.u.attr,
494         &lustre_sattr_dump_on_timeout.u.attr,
495         &lustre_sattr_dump_on_eviction.u.attr,
496         &lustre_sattr_at_min.u.attr,
497         &lustre_sattr_at_max.u.attr,
498         &lustre_sattr_at_extra.u.attr,
499         &lustre_sattr_at_early_margin.u.attr,
500         &lustre_sattr_at_history.u.attr,
501         &lustre_attr_memused_max.attr,
502         &lustre_attr_memused.attr,
503 #ifdef HAVE_SERVER_SUPPORT
504         &lustre_attr_enable_health_write.attr,
505         &lustre_sattr_ldlm_timeout.u.attr,
506         &lustre_sattr_bulk_timeout.u.attr,
507         &lustre_attr_no_transno.attr,
508 #endif
509         &lustre_sattr_lbug_on_eviction.u.attr,
510         &lustre_sattr_ping_interval.u.attr,
511         &lustre_sattr_evict_multiplier.u.attr,
512         NULL,
513 };
514
515 static void *obd_device_list_seq_start(struct seq_file *p, loff_t *pos)
516 {
517         struct obd_device *obd;
518         unsigned long devno;
519
520         devno = *pos;
521         obd_device_lock();
522         obd = obd_device_find(devno);
523
524         if (!obd) {
525                 obd_device_unlock();
526                 return NULL;
527         }
528
529         *pos = devno;
530         class_incref(obd, "obd_device_list_seq", obd);
531         obd_device_unlock();
532
533         return obd;
534 }
535
536 static void obd_device_list_seq_stop(struct seq_file *p, void *v)
537 {
538         struct obd_device *obd = v;
539
540         if (!obd)
541                 return;
542
543         obd_device_lock();
544         class_decref(obd, "obd_device_list_seq", obd);
545         obd_device_unlock();
546 }
547
548 static void *obd_device_list_seq_next(struct seq_file *p, void *v, loff_t *pos)
549 {
550         struct obd_device *obd = v;
551         unsigned long devno;
552
553         obd_device_lock();
554         class_decref(obd, "obd_device_list_seq", obd);
555         devno = *pos;
556         obd = obd_device_find_after(devno);
557
558         if (!obd) {
559                 (*pos)++;
560                 obd_device_unlock();
561                 return NULL;
562         }
563
564         *pos = devno;
565         class_incref(obd, "obd_device_list_seq", obd);
566         obd_device_unlock();
567
568         return obd;
569 }
570
571 static int obd_device_list_seq_show(struct seq_file *p, void *v)
572 {
573         struct obd_device *obd = v;
574         char *status;
575         int dev_no;
576
577         if (!obd)
578                 return 0;
579
580         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
581         dev_no = obd->obd_minor;
582
583         if (obd->obd_stopping)
584                 status = "ST";
585         else if (obd->obd_inactive)
586                 status = "IN";
587         else if (obd->obd_set_up)
588                 status = "UP";
589         else if (obd->obd_attached)
590                 status = "AT";
591         else
592                 status = "--";
593
594         seq_printf(p, "%3d %s %s %s %s %d\n",
595                    dev_no, status, obd->obd_type->typ_name,
596                    obd->obd_name, obd->obd_uuid.uuid,
597                    kref_read(&obd->obd_refcount));
598
599         return 0;
600 }
601
602 static const struct seq_operations obd_device_list_sops = {
603         .start = obd_device_list_seq_start,
604         .stop = obd_device_list_seq_stop,
605         .next = obd_device_list_seq_next,
606         .show = obd_device_list_seq_show,
607 };
608
609 static int obd_device_list_open(struct inode *inode, struct file *file)
610 {
611         struct seq_file *seq;
612         int rc = seq_open(file, &obd_device_list_sops);
613
614         if (rc)
615                 return rc;
616
617         seq = file->private_data;
618         seq->private = inode->i_private;
619         return 0;
620 }
621
622 static const struct file_operations obd_device_list_fops = {
623         .owner   = THIS_MODULE,
624         .open    = obd_device_list_open,
625         .read    = seq_read,
626         .llseek  = seq_lseek,
627         .release = seq_release,
628 };
629
630 /* checksum_speed */
631 static void *checksum_speed_start(struct seq_file *p, loff_t *pos)
632 {
633         return pos;
634 }
635
636 static void checksum_speed_stop(struct seq_file *p, void *v)
637 {
638 }
639
640 static void *checksum_speed_next(struct seq_file *p, void *v, loff_t *pos)
641 {
642         ++(*pos);
643         if (*pos >= CFS_HASH_ALG_SPEED_MAX - 1)
644                 return NULL;
645
646         return pos;
647 }
648
649 static int checksum_speed_show(struct seq_file *p, void *v)
650 {
651         loff_t index = *(loff_t *)v;
652
653         if (!index || index > CFS_HASH_ALG_SPEED_MAX - 1)
654                 return 0;
655
656         seq_printf(p, "%s: %d\n", cfs_crypto_hash_name(index),
657                    cfs_crypto_hash_speeds[index]);
658
659         return 0;
660 }
661
662 static const struct seq_operations checksum_speed_sops = {
663         .start = checksum_speed_start,
664         .stop = checksum_speed_stop,
665         .next = checksum_speed_next,
666         .show = checksum_speed_show,
667 };
668
669 static int checksum_speed_open(struct inode *inode, struct file *file)
670 {
671         int rc = seq_open(file, &checksum_speed_sops);
672
673         if (rc)
674                 return rc;
675
676         return 0;
677 }
678
679 static const struct file_operations checksum_speed_fops = {
680         .owner   = THIS_MODULE,
681         .open    = checksum_speed_open,
682         .read    = seq_read,
683         .llseek  = seq_lseek,
684         .release = seq_release,
685 };
686
687 static int
688 health_check_seq_show(struct seq_file *m, void *unused)
689 {
690         struct obd_device *obd = NULL;
691         unsigned long dev_no = 0;
692
693         obd_device_lock();
694         obd_device_for_each_cond(dev_no, obd, obd->obd_attached &&
695                                  obd->obd_set_up && !obd->obd_stopping) {
696                 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
697
698                 class_incref(obd, __func__, current);
699                 obd_device_unlock();
700                 if (obd_health_check(NULL, obd)) {
701                         seq_printf(m, "device %s reported unhealthy\n",
702                                    obd->obd_name);
703                 }
704                 obd_device_lock();
705                 class_decref(obd, __func__, current);
706         }
707         obd_device_unlock();
708
709         return 0;
710 }
711
712 LDEBUGFS_SEQ_FOPS_RO(health_check);
713
714 struct kset *lustre_kset;
715 EXPORT_SYMBOL_GPL(lustre_kset);
716
717 static struct attribute_group lustre_attr_group = {
718         .attrs = lustre_attrs,
719 };
720
721 ssize_t class_set_global(const char *param)
722 {
723         const char *value = strchr(param, '=') + 1;
724         size_t off = value - param - 1;
725         ssize_t count = -ENOENT;
726         int i;
727
728         for (i = 0; lustre_attrs[i]; i++) {
729                 if (!strncmp(lustre_attrs[i]->name, param, off)) {
730                         count = lustre_attr_store(&lustre_kset->kobj,
731                                                   lustre_attrs[i], value,
732                                                   strlen(value));
733                         break;
734                 }
735         }
736         return count;
737 }
738
739 int class_procfs_init(void)
740 {
741         struct proc_dir_entry *entry;
742         int rc = -ENOMEM;
743
744         ENTRY;
745
746         lustre_kset = kset_create_and_add("lustre", NULL, fs_kobj);
747         if (!lustre_kset)
748                 goto out;
749
750         /* Create the files associated with this kobject */
751         rc = sysfs_create_group(&lustre_kset->kobj, &lustre_attr_group);
752         if (rc) {
753                 kset_unregister(lustre_kset);
754                 goto out;
755         }
756
757         rc = jobid_cache_init();
758         if (rc) {
759                 kset_unregister(lustre_kset);
760                 goto out;
761         }
762
763         debugfs_lustre_root = debugfs_create_dir("lustre", NULL);
764
765         debugfs_create_file("devices", 0444, debugfs_lustre_root, NULL,
766                             &obd_device_list_fops);
767
768         debugfs_create_file("health_check", 0444, debugfs_lustre_root,
769                             NULL, &health_check_fops);
770
771         debugfs_create_file("checksum_speed", 0444, debugfs_lustre_root,
772                             NULL, &checksum_speed_fops);
773
774         entry = lprocfs_register("fs/lustre", NULL, NULL, NULL);
775         if (IS_ERR(entry)) {
776                 rc = PTR_ERR(entry);
777                 CERROR("cannot create '/proc/fs/lustre': rc = %d\n", rc);
778                 debugfs_remove_recursive(debugfs_lustre_root);
779                 kset_unregister(lustre_kset);
780                 goto out;
781         }
782
783         proc_lustre_root = entry;
784 out:
785         RETURN(rc);
786 }
787
788 int class_procfs_clean(void)
789 {
790         ENTRY;
791
792         debugfs_remove_recursive(debugfs_lustre_root);
793
794         debugfs_lustre_root = NULL;
795         jobid_cache_fini();
796
797         if (proc_lustre_root)
798                 lprocfs_remove(&proc_lustre_root);
799
800         sysfs_remove_group(&lustre_kset->kobj, &lustre_attr_group);
801
802         kset_unregister(lustre_kset);
803
804         RETURN(0);
805 }