From: James Simmons Date: Tue, 6 Feb 2018 16:43:07 +0000 (-0500) Subject: LU-9431 obd: resolve config log sysfs issues X-Git-Tag: 2.10.59~58 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=a74b2b5bce71367506e59f1bdba163eb21235a29 LU-9431 obd: resolve config log sysfs issues This resolves long standing issues with modifying sysfs settings on multiple nodes simultaneously by running a single command on the backend MGS server. Their are two ways to change the settings, LCFG_PARAM and LCFG_SET_PARAM. For the LCFG_PARAM case we create a new function class_modify_config() that grabs the attributes from the passed in kobject. We can use those attributes to modify the sysfs settings. If we can't find the attribute then send a uevent to let userland resolve the change. For the LCFG_SET_PARAM case we handle two class of settings. The function class_set_global() was modifiy to handle the top lustre sysfs files since they are not searchable with kset_find_obj. To make the new version of class_set_global() work both sets of sysfs attributes for the top level sysfs entries have been merged. If we can find a kobject with kset_find_obj then we can send a uevent so userland change manage the change. Change-Id: I4e7f19c4a232767119355c3c96e5752a10000da8 Signed-off-by: James Simmons Reviewed-on: https://review.whamcloud.com/30143 Tested-by: Jenkins Tested-by: Maloo Reviewed-by: Dmitry Eremin Reviewed-by: Ben Evans Reviewed-by: Sebastien Buisson Reviewed-by: Oleg Drokin --- diff --git a/lustre/conf/99-lustre.rules b/lustre/conf/99-lustre.rules index 7a0c6c7..acd5150 100644 --- a/lustre/conf/99-lustre.rules +++ b/lustre/conf/99-lustre.rules @@ -1 +1,3 @@ KERNEL=="obd", MODE="0666" +# set sysfs values on client +SUBSYSTEM=="lustre", ACTION=="change", ENV{PARAM}=="?*", RUN+="/usr/sbin/lctl set_param $env{PARAM}=$env{SETTING}" diff --git a/lustre/include/obd_class.h b/lustre/include/obd_class.h index 9a93448..9eb9ceb 100644 --- a/lustre/include/obd_class.h +++ b/lustre/include/obd_class.h @@ -140,6 +140,9 @@ struct lustre_cfg *lustre_cfg_rename(struct lustre_cfg *cfg, const char *new_name); void print_lustre_cfg(struct lustre_cfg *lcfg); int class_process_config(struct lustre_cfg *lcfg); +ssize_t class_set_global(const char *param); +ssize_t class_modify_config(struct lustre_cfg *lcfg, const char *prefix, + struct kobject *kobj); int class_process_proc_param(char *prefix, struct lprocfs_vars *lvars, struct lustre_cfg *lcfg, void *data); int class_attach(struct lustre_cfg *lcfg); @@ -1869,10 +1872,6 @@ int lustre_register_fs(void); int lustre_unregister_fs(void); int lustre_check_exclusion(struct super_block *sb, char *svname); -/* sysctl.c */ -extern int obd_sysctl_init(void); -extern void obd_sysctl_clean(void); - typedef __u8 class_uuid_t[16]; static inline void class_uuid_unparse(class_uuid_t uu, struct obd_uuid *out) { diff --git a/lustre/obdclass/Makefile.in b/lustre/obdclass/Makefile.in index b684e3c..4b2ea1e 100644 --- a/lustre/obdclass/Makefile.in +++ b/lustre/obdclass/Makefile.in @@ -1,6 +1,6 @@ MODULES := obdclass llog_test -obdclass-linux-objs := linux-module.o linux-obdo.o linux-sysctl.o +obdclass-linux-objs := linux-module.o linux-obdo.o obdclass-linux-objs := $(addprefix linux/,$(obdclass-linux-objs)) default: all diff --git a/lustre/obdclass/class_obd.c b/lustre/obdclass/class_obd.c index fbbf3a9..59be17a 100644 --- a/lustre/obdclass/class_obd.c +++ b/lustre/obdclass/class_obd.c @@ -529,7 +529,6 @@ cleanup_lu_global: lu_global_fini(); cleanup_class_procfs: - obd_sysctl_clean(); class_procfs_clean(); cleanup_caches: @@ -599,7 +598,6 @@ static void __exit obdclass_exit(void) lu_global_fini(); obd_cleanup_caches(); - obd_sysctl_clean(); class_procfs_clean(); diff --git a/lustre/obdclass/linux/Makefile.am b/lustre/obdclass/linux/Makefile.am index 2998055..7d1d31d 100644 --- a/lustre/obdclass/linux/Makefile.am +++ b/lustre/obdclass/linux/Makefile.am @@ -1,4 +1,3 @@ EXTRA_DIST = \ linux-module.c \ - linux-sysctl.c \ linux-obdo.c diff --git a/lustre/obdclass/linux/linux-module.c b/lustre/obdclass/linux/linux-module.c index 7fd9aa3..4b2d257 100644 --- a/lustre/obdclass/linux/linux-module.c +++ b/lustre/obdclass/linux/linux-module.c @@ -273,6 +273,112 @@ struct miscdevice obd_psdev = { .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 + +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) { @@ -431,6 +537,22 @@ static struct attribute *lustre_attrs[] = { &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, }; @@ -518,6 +640,24 @@ static struct attribute_group lustre_attr_group = { .attrs = lustre_attrs, }; +ssize_t class_set_global(const char *param) +{ + 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; +} + int class_procfs_init(void) { struct proc_dir_entry *entry; @@ -536,12 +676,6 @@ int class_procfs_init(void) goto out; } - rc = obd_sysctl_init(); - if (rc) { - kset_unregister(lustre_kset); - goto out; - } - rc = jobid_cache_init(); if (rc) { kset_unregister(lustre_kset); diff --git a/lustre/obdclass/linux/linux-sysctl.c b/lustre/obdclass/linux/linux-sysctl.c deleted file mode 100644 index 7d59b26..0000000 --- a/lustre/obdclass/linux/linux-sysctl.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see - * http://www.gnu.org/licenses/gpl-2.0.html - * - * GPL HEADER END - */ -/* - * Copyright (c) 1999, 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/ - * Lustre is a trademark of Sun Microsystems, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEBUG_SUBSYSTEM S_CLASS - -#include -#include -#include - -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); - -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); - -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 - -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 struct attribute *lustre_attrs[] = { - &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, -}; - -static struct attribute_group lustre_attr_group = { - .attrs = lustre_attrs, -}; - -int obd_sysctl_init(void) -{ - return sysfs_create_group(&lustre_kset->kobj, &lustre_attr_group); -} - -void obd_sysctl_clean(void) -{ - sysfs_remove_group(&lustre_kset->kobj, &lustre_attr_group); -} diff --git a/lustre/obdclass/obd_config.c b/lustre/obdclass/obd_config.c index 3ebf941..aaab911 100644 --- a/lustre/obdclass/obd_config.c +++ b/lustre/obdclass/obd_config.c @@ -36,6 +36,7 @@ #define DEBUG_SUBSYSTEM S_CLASS +#include #include #include @@ -947,34 +948,13 @@ void class_del_profiles(void) } EXPORT_SYMBOL(class_del_profiles); -static int class_set_global(char *ptr, int val, struct lustre_cfg *lcfg) -{ - ENTRY; - if (class_match_param(ptr, PARAM_AT_MIN, NULL) == 0) - at_min = val; - else if (class_match_param(ptr, PARAM_AT_MAX, NULL) == 0) - at_max = val; - else if (class_match_param(ptr, PARAM_AT_EXTRA, NULL) == 0) - at_extra = val; - else if (class_match_param(ptr, PARAM_AT_EARLY_MARGIN, NULL) == 0) - at_early_margin = val; - else if (class_match_param(ptr, PARAM_AT_HISTORY, NULL) == 0) - at_history = val; - else if (class_match_param(ptr, PARAM_JOBID_VAR, NULL) == 0) - strlcpy(obd_jobid_var, lustre_cfg_string(lcfg, 2), - JOBSTATS_JOBID_VAR_MAX_LEN + 1); - else - RETURN(-EINVAL); - - CDEBUG(D_IOCTL, "global %s = %d\n", ptr, val); - RETURN(0); -} - - /* We can't call ll_process_config or lquota_process_config directly because - * it lives in a module that must be loaded after this one. */ + * it lives in a module that must be loaded after this one. + */ static int (*client_process_config)(struct lustre_cfg *lcfg) = NULL; +#ifdef HAVE_SERVER_SUPPORT static int (*quota_process_config)(struct lustre_cfg *lcfg) = NULL; +#endif /* HAVE_SERVER_SUPPORT */ void lustre_register_client_process_config(int (*cpc)(struct lustre_cfg *lcfg)) { @@ -1057,10 +1037,12 @@ out_nocfg: } EXPORT_SYMBOL(lustre_cfg_rename); -static int process_param2_config(struct lustre_cfg *lcfg) +static ssize_t process_param2_config(struct lustre_cfg *lcfg) { char *param = lustre_cfg_string(lcfg, 1); char *upcall = lustre_cfg_string(lcfg, 2); + struct kobject *kobj = NULL; + const char *subsys = param; char *argv[] = { [0] = "/usr/sbin/lctl", [1] = "set_param", @@ -1069,8 +1051,44 @@ static int process_param2_config(struct lustre_cfg *lcfg) }; ktime_t start; ktime_t end; - int rc; + size_t len; + int rc; + ENTRY; + print_lustre_cfg(lcfg); + + len = strcspn(param, ".="); + if (!len) + return -EINVAL; + + /* If we find '=' then its the top level sysfs directory */ + if (param[len] == '=') + return class_set_global(param); + + subsys = kstrndup(param, len, GFP_KERNEL); + if (!subsys) + return -ENOMEM; + + kobj = kset_find_obj(lustre_kset, subsys); + kfree(subsys); + if (kobj) { + char *value = param; + char *envp[3]; + int i; + + param = strsep(&value, "="); + envp[0] = kasprintf(GFP_KERNEL, "PARAM=%s", param); + envp[1] = kasprintf(GFP_KERNEL, "SETTING=%s", value); + envp[2] = NULL; + + rc = kobject_uevent_env(kobj, KOBJ_CHANGE, envp); + for (i = 0; i < ARRAY_SIZE(envp); i++) + kfree(envp[i]); + + kobject_put(kobj); + + RETURN(rc); + } /* Add upcall processing here. Now only lctl is supported */ if (strcmp(upcall, LCTL_UPCALL) != 0) { @@ -1096,11 +1114,13 @@ static int process_param2_config(struct lustre_cfg *lcfg) RETURN(rc); } +#ifdef HAVE_SERVER_SUPPORT void lustre_register_quota_process_config(int (*qpc)(struct lustre_cfg *lcfg)) { quota_process_config = qpc; } EXPORT_SYMBOL(lustre_register_quota_process_config); +#endif /* HAVE_SERVER_SUPPORT */ /** Process configuration commands given in lustre_cfg form. * These may come from direct calls (e.g. class_manual_cleanup) @@ -1196,20 +1216,22 @@ int class_process_config(struct lustre_cfg *lcfg) } else if ((class_match_param(lustre_cfg_string(lcfg, 1), PARAM_SYS, &tmp) == 0)) { /* Global param settings */ - err = class_set_global(tmp, lcfg->lcfg_num, lcfg); + err = class_set_global(tmp); /* * Client or server should not fail to mount if * it hits an unknown configuration parameter. */ - if (err != 0) + if (err < 0) CWARN("Ignoring unknown param %s\n", tmp); GOTO(out, err = 0); +#ifdef HAVE_SERVER_SUPPORT } else if ((class_match_param(lustre_cfg_string(lcfg, 1), PARAM_QUOTA, &tmp) == 0) && quota_process_config) { err = (*quota_process_config)(lcfg); GOTO(out, err); +#endif /* HAVE_SERVER_SUPPORT */ } break; @@ -1320,6 +1342,90 @@ out: } EXPORT_SYMBOL(class_process_config); +ssize_t class_modify_config(struct lustre_cfg *lcfg, const char *prefix, + struct kobject *kobj) +{ + struct kobj_type *typ; + ssize_t count = 0; + int i; + + if (lcfg->lcfg_command != LCFG_PARAM) { + CERROR("Unknown command: %d\n", lcfg->lcfg_command); + return -EINVAL; + } + + typ = get_ktype(kobj); + if (!typ || !typ->default_attrs) + return -ENODEV; + + print_lustre_cfg(lcfg); + + /* + * e.g. tunefs.lustre --param mdt.group_upcall=foo /r/tmp/lustre-mdt + * or lctl conf_param lustre-MDT0000.mdt.group_upcall=bar + * or lctl conf_param lustre-OST0000.osc.max_dirty_mb=36 + */ + for (i = 1; i < lcfg->lcfg_bufcount; i++) { + struct attribute *attr; + size_t keylen; + char *value; + char *key; + int j; + + key = lustre_cfg_buf(lcfg, i); + /* Strip off prefix */ + if (class_match_param(key, prefix, &key)) + /* If the prefix doesn't match, return error so we + * can pass it down the stack + */ + return -ENOSYS; + + value = strchr(key, '='); + if (!value || *(value + 1) == 0) { + CERROR("%s: can't parse param '%s' (missing '=')\n", + lustre_cfg_string(lcfg, 0), + lustre_cfg_string(lcfg, i)); + /* continue parsing other params */ + continue; + } + keylen = value - key; + value++; + + attr = NULL; + for (j = 0; typ->default_attrs[j]; j++) { + if (!strncmp(typ->default_attrs[j]->name, key, + keylen)) { + attr = typ->default_attrs[j]; + break; + } + } + + if (!attr) { + char *envp[3]; + + envp[0] = kasprintf(GFP_KERNEL, "PARAM=%s.%s.%.*s", + kobject_name(kobj->parent), + kobject_name(kobj), + (int) keylen, key); + envp[1] = kasprintf(GFP_KERNEL, "SETTING=%s", value); + envp[2] = NULL; + + if (kobject_uevent_env(kobj, KOBJ_CHANGE, envp)) { + CERROR("%s: failed to send uevent %s\n", + kobject_name(kobj), key); + } + + for (i = 0; i < ARRAY_SIZE(envp); i++) + kfree(envp[i]); + } else { + count += lustre_attr_store(kobj, attr, value, + strlen(value)); + } + } + return count; +} +EXPORT_SYMBOL(class_modify_config); + int class_process_proc_param(char *prefix, struct lprocfs_vars *lvars, struct lustre_cfg *lcfg, void *data) {