X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Fobdclass%2Flinux%2Flinux-module.c;h=464d288731ac4dea070938340a42719948ee5dc2;hp=f8b71955ba6f52ae723f7115dae4353921bc5e37;hb=6488c0ec57de2d188bd15e502917b762e3a9dd1d;hpb=bef2828d5dbe56fd0a59c2a260794771f89795b8;ds=sidebyside diff --git a/lustre/obdclass/linux/linux-module.c b/lustre/obdclass/linux/linux-module.c index f8b71955..464d288 100644 --- a/lustre/obdclass/linux/linux-module.c +++ b/lustre/obdclass/linux/linux-module.c @@ -1,6 +1,4 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * +/* * GPL HEADER START * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -17,17 +15,15 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. + * + * Copyright (c) 2011, 2017, Intel Corporation. */ /* * This file is part of Lustre, http://www.lustre.org/ @@ -41,18 +37,10 @@ */ #define DEBUG_SUBSYSTEM S_CLASS -#ifndef EXPORT_SYMTAB -# define EXPORT_SYMTAB -#endif -#ifdef __KERNEL__ -#ifndef AUTOCONF_INCLUDED -#include /* for CONFIG_PROC_FS */ -#endif #include #include #include -#include #include #include #include @@ -68,40 +56,108 @@ #include #include #include -#include #include #include #include -#include #include -#else -# include -#endif +#include #include #include #include -#include #include -#include -#include -#ifdef __KERNEL__ -#include +#include +#include +#include + +#define OBD_MAX_IOCTL_BUFFER 8192 -int proc_version; +static int obd_ioctl_is_invalid(struct obd_ioctl_data *data) +{ + if (data->ioc_len > BIT(30)) { + CERROR("OBD ioctl: ioc_len larger than 1<<30\n"); + return 1; + } + + if (data->ioc_inllen1 > BIT(30)) { + CERROR("OBD ioctl: ioc_inllen1 larger than 1<<30\n"); + return 1; + } + + if (data->ioc_inllen2 > BIT(30)) { + CERROR("OBD ioctl: ioc_inllen2 larger than 1<<30\n"); + return 1; + } + + if (data->ioc_inllen3 > BIT(30)) { + CERROR("OBD ioctl: ioc_inllen3 larger than 1<<30\n"); + return 1; + } + + if (data->ioc_inllen4 > BIT(30)) { + CERROR("OBD ioctl: ioc_inllen4 larger than 1<<30\n"); + return 1; + } + + if (data->ioc_inlbuf1 && data->ioc_inllen1 == 0) { + CERROR("OBD ioctl: inlbuf1 pointer but 0 length\n"); + return 1; + } + + if (data->ioc_inlbuf2 && data->ioc_inllen2 == 0) { + CERROR("OBD ioctl: inlbuf2 pointer but 0 length\n"); + return 1; + } + + if (data->ioc_inlbuf3 && data->ioc_inllen3 == 0) { + CERROR("OBD ioctl: inlbuf3 pointer but 0 length\n"); + return 1; + } + + if (data->ioc_inlbuf4 && data->ioc_inllen4 == 0) { + CERROR("OBD ioctl: inlbuf4 pointer but 0 length\n"); + return 1; + } + + if (data->ioc_pbuf1 && data->ioc_plen1 == 0) { + CERROR("OBD ioctl: pbuf1 pointer but 0 length\n"); + return 1; + } + + if (data->ioc_pbuf2 && data->ioc_plen2 == 0) { + CERROR("OBD ioctl: pbuf2 pointer but 0 length\n"); + return 1; + } + + if (!data->ioc_pbuf1 && data->ioc_plen1 != 0) { + CERROR("OBD ioctl: plen1 set but NULL pointer\n"); + return 1; + } + + if (!data->ioc_pbuf2 && data->ioc_plen2 != 0) { + CERROR("OBD ioctl: plen2 set but NULL pointer\n"); + return 1; + } + + if (obd_ioctl_packlen(data) > data->ioc_len) { + CERROR("OBD ioctl: packlen exceeds ioc_len (%d > %d)\n", + obd_ioctl_packlen(data), data->ioc_len); + return 1; + } + + return 0; +} /* buffer MUST be at least the size of obd_ioctl_hdr */ -int obd_ioctl_getdata(char **buf, int *len, void *arg) +int obd_ioctl_getdata(char **buf, int *len, void __user *arg) { - struct obd_ioctl_hdr hdr; - struct obd_ioctl_data *data; - int err; - int offset = 0; - ENTRY; + struct obd_ioctl_hdr hdr; + struct obd_ioctl_data *data; + int offset = 0; + ENTRY; - err = cfs_copy_from_user(&hdr, (void *)arg, sizeof(hdr)); - if ( err ) - RETURN(err); + if (copy_from_user(&hdr, arg, sizeof(hdr))) + RETURN(-EFAULT); if (hdr.ioc_version != OBD_IOCTL_VERSION) { CERROR("Version mismatch kernel (%x) vs application (%x)\n", @@ -133,11 +189,10 @@ int obd_ioctl_getdata(char **buf, int *len, void *arg) *len = hdr.ioc_len; data = (struct obd_ioctl_data *)*buf; - err = cfs_copy_from_user(*buf, (void *)arg, hdr.ioc_len); - if ( err ) { - OBD_FREE_LARGE(*buf, hdr.ioc_len); - RETURN(err); - } + if (copy_from_user(*buf, arg, hdr.ioc_len)) { + OBD_FREE_LARGE(*buf, hdr.ioc_len); + RETURN(-EFAULT); + } if (obd_ioctl_is_invalid(data)) { CERROR("ioctl not correctly formatted\n"); @@ -160,53 +215,34 @@ int obd_ioctl_getdata(char **buf, int *len, void *arg) offset += cfs_size_round(data->ioc_inllen3); } - if (data->ioc_inllen4) { - data->ioc_inlbuf4 = &data->ioc_bulk[0] + offset; - } + if (data->ioc_inllen4) + data->ioc_inlbuf4 = &data->ioc_bulk[0] + offset; - EXIT; - return 0; + RETURN(0); } - -int obd_ioctl_popdata(void *arg, void *data, int len) -{ - int err; - - err = cfs_copy_to_user(arg, data, len); - if (err) - err = -EFAULT; - return err; -} - EXPORT_SYMBOL(obd_ioctl_getdata); -EXPORT_SYMBOL(obd_ioctl_popdata); /* opening /dev/obd */ static int obd_class_open(struct inode * inode, struct file * file) { - ENTRY; + ENTRY; - PORTAL_MODULE_USE; - RETURN(0); + try_module_get(THIS_MODULE); + RETURN(0); } /* closing /dev/obd */ static int obd_class_release(struct inode * inode, struct file * file) { - ENTRY; + ENTRY; - PORTAL_MODULE_UNUSE; - RETURN(0); + module_put(THIS_MODULE); + RETURN(0); } /* to control /dev/obd */ -#ifdef HAVE_UNLOCKED_IOCTL static long obd_class_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -#else -static int obd_class_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -#endif + unsigned long arg) { int err = 0; ENTRY; @@ -224,118 +260,303 @@ static int obd_class_ioctl(struct inode *inode, struct file *filp, /* declare character device */ static struct file_operations obd_psdev_fops = { - .owner = THIS_MODULE, -#if HAVE_UNLOCKED_IOCTL - .unlocked_ioctl = obd_class_ioctl, /* unlocked_ioctl */ -#else - .ioctl = obd_class_ioctl, /* ioctl */ -#endif - .open = obd_class_open, /* open */ - .release = obd_class_release, /* release */ + .owner = THIS_MODULE, + .unlocked_ioctl = obd_class_ioctl, /* unlocked_ioctl */ + .open = obd_class_open, /* open */ + .release = obd_class_release, /* release */ }; /* modules setup */ -cfs_psdev_t obd_psdev = { - .minor = OBD_DEV_MINOR, - .name = OBD_DEV_NAME, - .fops = &obd_psdev_fops, +struct miscdevice obd_psdev = { + .minor = MISC_DYNAMIC_MINOR, + .name = OBD_DEV_NAME, + .fops = &obd_psdev_fops, }; +struct static_lustre_uintvalue_attr { + struct { + struct attribute attr; + ssize_t (*show)(struct kobject *kobj, struct attribute *attr, + char *buf); + ssize_t (*store)(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t len); + } u; + int *value; +}; + +static ssize_t static_uintvalue_show(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + struct static_lustre_uintvalue_attr *lattr = (void *)attr; + + return sprintf(buf, "%d\n", *lattr->value); +} + +static ssize_t static_uintvalue_store(struct kobject *kobj, + struct attribute *attr, + const char *buffer, size_t count) +{ + struct static_lustre_uintvalue_attr *lattr = (void *)attr; + unsigned int val; + int rc; + + rc = kstrtouint(buffer, 10, &val); + if (rc) + return rc; + + *lattr->value = val; + + return count; +} + +#define LUSTRE_STATIC_UINT_ATTR(name, value) \ +static struct static_lustre_uintvalue_attr lustre_sattr_##name = \ + { __ATTR(name, 0644, static_uintvalue_show, \ + static_uintvalue_store), value } + +LUSTRE_STATIC_UINT_ATTR(timeout, &obd_timeout); +LUSTRE_STATIC_UINT_ATTR(debug_peer_on_timeout, &obd_debug_peer_on_timeout); +LUSTRE_STATIC_UINT_ATTR(dump_on_timeout, &obd_dump_on_timeout); +LUSTRE_STATIC_UINT_ATTR(dump_on_eviction, &obd_dump_on_eviction); +LUSTRE_STATIC_UINT_ATTR(at_min, &at_min); +LUSTRE_STATIC_UINT_ATTR(at_max, &at_max); +LUSTRE_STATIC_UINT_ATTR(at_extra, &at_extra); +LUSTRE_STATIC_UINT_ATTR(at_early_margin, &at_early_margin); +LUSTRE_STATIC_UINT_ATTR(at_history, &at_history); + +#ifdef HAVE_SERVER_SUPPORT +LUSTRE_STATIC_UINT_ATTR(ldlm_timeout, &ldlm_timeout); +LUSTRE_STATIC_UINT_ATTR(bulk_timeout, &bulk_timeout); #endif -#ifdef LPROCFS -int obd_proc_read_version(char *page, char **start, off_t off, int count, - int *eof, void *data) +static ssize_t memused_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + return sprintf(buf, "%llu\n", obd_memory_sum()); +} +LUSTRE_RO_ATTR(memused); + +static ssize_t memused_max_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + return sprintf(buf, "%llu\n", obd_memory_max()); +} +LUSTRE_RO_ATTR(memused_max); + +static ssize_t max_dirty_mb_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + return sprintf(buf, "%lu\n", + obd_max_dirty_pages / (1 << (20 - PAGE_SHIFT))); +} + +static ssize_t max_dirty_mb_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count) +{ + unsigned long val; + int rc; + + rc = kstrtoul(buffer, 10, &val); + if (rc) + return rc; + + val *= 1 << (20 - PAGE_SHIFT); /* convert to pages */ + + if (val > ((totalram_pages / 10) * 9)) { + /* Somebody wants to assign too much memory to dirty pages */ + return -EINVAL; + } + + if (val < 4 << (20 - PAGE_SHIFT)) { + /* Less than 4 Mb for dirty cache is also bad */ + return -EINVAL; + } + + obd_max_dirty_pages = val; + + return count; +} +LUSTRE_RW_ATTR(max_dirty_mb); + +static ssize_t version_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - *eof = 1; - return snprintf(page, count, "lustre: %s\nkernel: %s\nbuild: %s\n", - LUSTRE_VERSION_STRING, "patchless_client", - BUILD_VERSION); + return sprintf(buf, "%s\n", LUSTRE_VERSION_STRING); } -int obd_proc_read_pinger(char *page, char **start, off_t off, int count, - int *eof, void *data) +static ssize_t pinger_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - *eof = 1; - return snprintf(page, count, "%s\n", #ifdef ENABLE_PINGER - "on" + const char *state = "on"; #else - "off" + const char *state = "off"; #endif - ); + return sprintf(buf, "%s\n", state); } /** * Check all obd devices health * - * \param page - * \param start - * \param off - * \param count - * \param eof - * \param data - * proc read function parameters, please refer to kernel - * code fs/proc/generic.c proc_file_read() - * \param data [in] unused + * \param kobj + * \param buf [in] * - * \retval number of characters printed + * \retval number of characters printed if healthy */ -static int obd_proc_read_health(char *page, char **start, off_t off, - int count, int *eof, void *data) +static ssize_t +health_check_show(struct kobject *kobj, struct attribute *attr, char *buf) { - int rc = 0, i; - *eof = 1; - - if (libcfs_catastrophe) - rc += snprintf(page + rc, count - rc, "LBUG\n"); - - cfs_read_lock(&obd_dev_lock); - for (i = 0; i < class_devno_max(); i++) { - struct obd_device *obd; - - obd = class_num2obd(i); - if (obd == NULL || !obd->obd_attached || !obd->obd_set_up) - continue; - - LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC); - if (obd->obd_stopping) - continue; - - class_incref(obd, __FUNCTION__, cfs_current()); - cfs_read_unlock(&obd_dev_lock); - - if (obd_health_check(obd)) { - rc += snprintf(page + rc, count - rc, - "device %s reported unhealthy\n", - obd->obd_name); - } - class_decref(obd, __FUNCTION__, cfs_current()); - cfs_read_lock(&obd_dev_lock); - } - cfs_read_unlock(&obd_dev_lock); + bool healthy = true; + size_t len = 0; + int i; + + if (libcfs_catastrophe) { + len = sprintf(buf, "LBUG\n"); + healthy = false; + } + + read_lock(&obd_dev_lock); + for (i = 0; i < class_devno_max(); i++) { + struct obd_device *obd; + + obd = class_num2obd(i); + if (obd == NULL || !obd->obd_attached || !obd->obd_set_up) + continue; + + LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC); + if (obd->obd_stopping) + continue; + + class_incref(obd, __FUNCTION__, current); + read_unlock(&obd_dev_lock); + + if (obd_health_check(NULL, obd)) { + len = sprintf(buf, "device %s reported unhealthy\n", + obd->obd_name); + healthy = false; + } + class_decref(obd, __FUNCTION__, current); + read_lock(&obd_dev_lock); + } + read_unlock(&obd_dev_lock); + + if (healthy) + len = sprintf(buf, "healthy\n"); + else + len = sprintf(buf, "NOT HEALTHY\n"); + + return len; +} + +static ssize_t jobid_var_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + int rc = 0; - if (rc == 0) - return snprintf(page, count, "healthy\n"); + if (strlen(obd_jobid_var)) + rc = snprintf(buf, PAGE_SIZE, "%s\n", obd_jobid_var); + return rc; +} + +static ssize_t jobid_var_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count) +{ + if (!count || count > JOBSTATS_JOBID_VAR_MAX_LEN) + return -EINVAL; + + memset(obd_jobid_var, 0, JOBSTATS_JOBID_VAR_MAX_LEN + 1); - rc += snprintf(page + rc, count - rc, "NOT HEALTHY\n"); - return rc; + memcpy(obd_jobid_var, buffer, count); + + /* Trim the trailing '\n' if any */ + if (obd_jobid_var[count - 1] == '\n') + obd_jobid_var[count - 1] = 0; + + return count; } +static ssize_t jobid_name_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + int rc = 0; + + if (strlen(obd_jobid_name)) + rc = snprintf(buf, PAGE_SIZE, "%s\n", obd_jobid_name); + return rc; +} + +static ssize_t jobid_name_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count) +{ + if (!count || count > LUSTRE_JOBID_SIZE) + return -EINVAL; + + if (strcmp(obd_jobid_var, JOBSTATS_NODELOCAL) != 0 && + !strchr(buffer, '%')) { + lustre_jobid_clear(buffer); + return count; + } + + /* clear previous value */ + memset(obd_jobid_name, 0, LUSTRE_JOBID_SIZE); + + memcpy(obd_jobid_name, buffer, count); + + /* Trim the trailing '\n' if any */ + if (obd_jobid_name[count - 1] == '\n') { + /* Don't echo just a newline */ + if (count == 1) + return -EINVAL; + obd_jobid_name[count - 1] = 0; + } + + return count; +} + +/* Root for /sys/kernel/debug/lustre */ +struct dentry *debugfs_lustre_root; +EXPORT_SYMBOL_GPL(debugfs_lustre_root); + +#ifdef CONFIG_PROC_FS /* Root for /proc/fs/lustre */ struct proc_dir_entry *proc_lustre_root = NULL; - -struct lprocfs_vars lprocfs_base[] = { - { "version", obd_proc_read_version, NULL, NULL }, - { "pinger", obd_proc_read_pinger, NULL, NULL }, - { "health_check", obd_proc_read_health, NULL, NULL }, - { 0 } -}; +EXPORT_SYMBOL(proc_lustre_root); #else #define lprocfs_base NULL -#endif /* LPROCFS */ +#endif /* CONFIG_PROC_FS */ + +LUSTRE_RO_ATTR(version); +LUSTRE_RO_ATTR(pinger); +LUSTRE_RO_ATTR(health_check); +LUSTRE_RW_ATTR(jobid_var); +LUSTRE_RW_ATTR(jobid_name); + +static struct attribute *lustre_attrs[] = { + &lustre_attr_version.attr, + &lustre_attr_pinger.attr, + &lustre_attr_health_check.attr, + &lustre_attr_jobid_name.attr, + &lustre_attr_jobid_var.attr, + &lustre_sattr_timeout.u.attr, + &lustre_attr_max_dirty_mb.attr, + &lustre_sattr_debug_peer_on_timeout.u.attr, + &lustre_sattr_dump_on_timeout.u.attr, + &lustre_sattr_dump_on_eviction.u.attr, + &lustre_sattr_at_min.u.attr, + &lustre_sattr_at_max.u.attr, + &lustre_sattr_at_extra.u.attr, + &lustre_sattr_at_early_margin.u.attr, + &lustre_sattr_at_history.u.attr, + &lustre_attr_memused_max.attr, + &lustre_attr_memused.attr, +#ifdef HAVE_SERVER_SUPPORT + &lustre_sattr_ldlm_timeout.u.attr, + &lustre_sattr_bulk_timeout.u.attr, +#endif + NULL, +}; -#ifdef __KERNEL__ static void *obd_device_list_seq_start(struct seq_file *p, loff_t *pos) { if (*pos >= class_devno_max()) @@ -378,13 +599,14 @@ static int obd_device_list_seq_show(struct seq_file *p, void *v) else status = "--"; - return seq_printf(p, "%3d %s %s %s %s %d\n", - (int)index, status, obd->obd_type->typ_name, - obd->obd_name, obd->obd_uuid.uuid, - cfs_atomic_read(&obd->obd_refcount)); + seq_printf(p, "%3d %s %s %s %s %d\n", + (int)index, status, obd->obd_type->typ_name, + obd->obd_name, obd->obd_uuid.uuid, + atomic_read(&obd->obd_refcount)); + return 0; } -struct seq_operations obd_device_list_sops = { +static const struct seq_operations obd_device_list_sops = { .start = obd_device_list_seq_start, .stop = obd_device_list_seq_stop, .next = obd_device_list_seq_next, @@ -393,68 +615,121 @@ struct seq_operations obd_device_list_sops = { static int obd_device_list_open(struct inode *inode, struct file *file) { - struct proc_dir_entry *dp = PDE(inode); - struct seq_file *seq; - int rc = seq_open(file, &obd_device_list_sops); - - if (rc) - return rc; + struct seq_file *seq; + int rc = seq_open(file, &obd_device_list_sops); - seq = file->private_data; - seq->private = dp->data; + if (rc) + return rc; - return 0; + seq = file->private_data; + seq->private = inode->i_private; + return 0; } -struct file_operations obd_device_list_fops = { +static const struct file_operations obd_device_list_fops = { .owner = THIS_MODULE, .open = obd_device_list_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; -#endif -int class_procfs_init(void) +struct kset *lustre_kset; +EXPORT_SYMBOL_GPL(lustre_kset); + +static struct attribute_group lustre_attr_group = { + .attrs = lustre_attrs, +}; + +ssize_t class_set_global(const char *param) { -#ifdef __KERNEL__ - int rc; - ENTRY; + const char *value = strchr(param, '=') + 1; + size_t off = value - param - 1; + ssize_t count = -ENOENT; + int i; + + for (i = 0; lustre_attrs[i]; i++) { + if (!strncmp(lustre_attrs[i]->name, param, off)) { + count = lustre_attr_store(&lustre_kset->kobj, + lustre_attrs[i], value, + strlen(value)); + break; + } + } + return count; +} - obd_sysctl_init(); - proc_lustre_root = lprocfs_register("fs/lustre", NULL, - lprocfs_base, NULL); - rc = lprocfs_seq_create(proc_lustre_root, "devices", 0444, - &obd_device_list_fops, NULL); - if (rc) - CERROR("error adding /proc/fs/lustre/devices file\n"); -#else - ENTRY; -#endif - RETURN(0); +int class_procfs_init(void) +{ + struct proc_dir_entry *entry; + struct dentry *file; + int rc = -ENOMEM; + ENTRY; + + lustre_kset = kset_create_and_add("lustre", NULL, fs_kobj); + if (!lustre_kset) + goto out; + + /* Create the files associated with this kobject */ + rc = sysfs_create_group(&lustre_kset->kobj, &lustre_attr_group); + if (rc) { + kset_unregister(lustre_kset); + goto out; + } + + rc = jobid_cache_init(); + if (rc) { + kset_unregister(lustre_kset); + goto out; + } + + debugfs_lustre_root = debugfs_create_dir("lustre", NULL); + if (IS_ERR_OR_NULL(debugfs_lustre_root)) { + rc = debugfs_lustre_root ? PTR_ERR(debugfs_lustre_root) + : -ENOMEM; + debugfs_lustre_root = NULL; + kset_unregister(lustre_kset); + goto out; + } + + file = debugfs_create_file("devices", 0444, debugfs_lustre_root, NULL, + &obd_device_list_fops); + if (IS_ERR_OR_NULL(file)) { + rc = file ? PTR_ERR(file) : -ENOMEM; + debugfs_remove(debugfs_lustre_root); + kset_unregister(lustre_kset); + goto out; + } + + entry = lprocfs_register("fs/lustre", NULL, NULL, NULL); + if (IS_ERR(entry)) { + rc = PTR_ERR(entry); + CERROR("cannot create '/proc/fs/lustre': rc = %d\n", rc); + debugfs_remove_recursive(debugfs_lustre_root); + kset_unregister(lustre_kset); + goto out; + } + + proc_lustre_root = entry; +out: + RETURN(rc); } -#ifdef __KERNEL__ int class_procfs_clean(void) { - ENTRY; - if (proc_lustre_root) { - lprocfs_remove(&proc_lustre_root); - } - RETURN(0); -} + ENTRY; + debugfs_remove_recursive(debugfs_lustre_root); -/* Check that we're building against the appropriate version of the Lustre - * kernel patch */ -#include -#ifdef LUSTRE_KERNEL_VERSION -#define LUSTRE_MIN_VERSION 45 -#define LUSTRE_MAX_VERSION 47 -#if (LUSTRE_KERNEL_VERSION < LUSTRE_MIN_VERSION) -# error Cannot continue: Your Lustre kernel patch is older than the sources -#elif (LUSTRE_KERNEL_VERSION > LUSTRE_MAX_VERSION) -# error Cannot continue: Your Lustre sources are older than the kernel patch -#endif -#endif -#endif + debugfs_lustre_root = NULL; + jobid_cache_fini(); + + if (proc_lustre_root) + lprocfs_remove(&proc_lustre_root); + + sysfs_remove_group(&lustre_kset->kobj, &lustre_attr_group); + + kset_unregister(lustre_kset); + + RETURN(0); +}