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=8b114d2948f1bda36227b3c531b85d71f2f95328;hb=6488c0ec57de2d188bd15e502917b762e3a9dd1d;hpb=1ab4b0239bbd75b4c05f36b8d2cf04fb371b10c2 diff --git a/lustre/obdclass/linux/linux-module.c b/lustre/obdclass/linux/linux-module.c index 8b114d2..464d288 100644 --- a/lustre/obdclass/linux/linux-module.c +++ b/lustre/obdclass/linux/linux-module.c @@ -15,11 +15,7 @@ * * 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 */ @@ -27,7 +23,7 @@ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. * - * Copyright (c) 2011, 2012, Intel Corporation. + * Copyright (c) 2011, 2017, Intel Corporation. */ /* * This file is part of Lustre, http://www.lustre.org/ @@ -45,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -65,17 +60,93 @@ #include #include #include +#include #include #include #include -#include #include -#include -#include -#include +#include +#include +#include + +#define OBD_MAX_IOCTL_BUFFER 8192 + +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; + } -int proc_version; + 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 __user *arg) @@ -151,16 +222,6 @@ int obd_ioctl_getdata(char **buf, int *len, void __user *arg) } EXPORT_SYMBOL(obd_ioctl_getdata); -int obd_ioctl_popdata(void __user *arg, void *data, int len) -{ - int err; - ENTRY; - - err = copy_to_user(arg, data, len) ? -EFAULT : 0; - RETURN(err); -} -EXPORT_SYMBOL(obd_ioctl_popdata); - /* opening /dev/obd */ static int obd_class_open(struct inode * inode, struct file * file) { @@ -207,48 +268,153 @@ static struct file_operations obd_psdev_fops = { /* modules setup */ struct miscdevice obd_psdev = { - .minor = OBD_DEV_MINOR, - .name = OBD_DEV_NAME, - .fops = &obd_psdev_fops, + .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 -static int obd_proc_version_seq_show(struct seq_file *m, void *v) +static ssize_t memused_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - return seq_printf(m, "lustre: %s\nkernel: %s\nbuild: %s\n", - LUSTRE_VERSION_STRING, "patchless_client", - BUILD_VERSION); + return sprintf(buf, "%llu\n", obd_memory_sum()); } -LPROC_SEQ_FOPS_RO(obd_proc_version); +LUSTRE_RO_ATTR(memused); -static int obd_proc_pinger_seq_show(struct seq_file *m, void *v) +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) +{ + return sprintf(buf, "%s\n", LUSTRE_VERSION_STRING); +} + +static ssize_t pinger_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - return seq_printf(m, "%s\n", #ifdef ENABLE_PINGER - "on" + const char *state = "on"; #else - "off" + const char *state = "off"; #endif - ); + return sprintf(buf, "%s\n", state); } -LPROC_SEQ_FOPS_RO(obd_proc_pinger); /** * Check all obd devices health * - * \param seq_file - * \param data [in] unused + * \param kobj + * \param buf [in] * * \retval number of characters printed if healthy */ -static int obd_proc_health_seq_show(struct seq_file *m, void *data) +static ssize_t +health_check_show(struct kobject *kobj, struct attribute *attr, char *buf) { bool healthy = true; + size_t len = 0; int i; - if (libcfs_catastrophe) - seq_printf(m, "LBUG\n"); + if (libcfs_catastrophe) { + len = sprintf(buf, "LBUG\n"); + healthy = false; + } read_lock(&obd_dev_lock); for (i = 0; i < class_devno_max(); i++) { @@ -266,8 +432,8 @@ static int obd_proc_health_seq_show(struct seq_file *m, void *data) read_unlock(&obd_dev_lock); if (obd_health_check(NULL, obd)) { - seq_printf(m, "device %s reported unhealthy\n", - obd->obd_name); + len = sprintf(buf, "device %s reported unhealthy\n", + obd->obd_name); healthy = false; } class_decref(obd, __FUNCTION__, current); @@ -276,30 +442,32 @@ static int obd_proc_health_seq_show(struct seq_file *m, void *data) read_unlock(&obd_dev_lock); if (healthy) - return seq_printf(m, "healthy\n"); + len = sprintf(buf, "healthy\n"); + else + len = sprintf(buf, "NOT HEALTHY\n"); - seq_printf(m, "NOT HEALTHY\n"); - return 0; + return len; } -LPROC_SEQ_FOPS_RO(obd_proc_health); -static int obd_proc_jobid_var_seq_show(struct seq_file *m, void *v) +static ssize_t jobid_var_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - return seq_printf(m, "%s\n", obd_jobid_var); + int rc = 0; + + if (strlen(obd_jobid_var)) + rc = snprintf(buf, PAGE_SIZE, "%s\n", obd_jobid_var); + return rc; } -static ssize_t -obd_proc_jobid_var_seq_write(struct file *file, const char __user *buffer, - size_t count, loff_t *off) +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); - /* This might leave the var invalid on error, which is probably fine.*/ - if (copy_from_user(obd_jobid_var, buffer, count)) - return -EFAULT; + memcpy(obd_jobid_var, buffer, count); /* Trim the trailing '\n' if any */ if (obd_jobid_var[count - 1] == '\n') @@ -307,26 +475,87 @@ obd_proc_jobid_var_seq_write(struct file *file, const char __user *buffer, return count; } -LPROC_SEQ_FOPS(obd_proc_jobid_var); +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; EXPORT_SYMBOL(proc_lustre_root); - -struct lprocfs_seq_vars lprocfs_base[] = { - { .name = "version", - .fops = &obd_proc_version_fops }, - { .name = "pinger", - .fops = &obd_proc_pinger_fops }, - { .name = "health_check", - .fops = &obd_proc_health_fops }, - { .name = "jobid_var", - .fops = &obd_proc_jobid_var_fops}, - { 0 } -}; #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, +}; static void *obd_device_list_seq_start(struct seq_file *p, loff_t *pos) { @@ -370,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, - 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, @@ -392,11 +622,11 @@ static int obd_device_list_open(struct inode *inode, struct file *file) return rc; seq = file->private_data; - seq->private = PDE_DATA(inode); + 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, @@ -404,44 +634,102 @@ struct file_operations obd_device_list_fops = { .release = seq_release, }; +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) +{ + 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; - int rc; + struct dentry *file; + int rc = -ENOMEM; ENTRY; - obd_sysctl_init(); + lustre_kset = kset_create_and_add("lustre", NULL, fs_kobj); + if (!lustre_kset) + goto out; - entry = lprocfs_seq_register("fs/lustre", NULL, lprocfs_base, NULL); - if (IS_ERR(entry)) { - rc = PTR_ERR(entry); - CERROR("cannot create '/proc/fs/lustre': rc = %d\n", rc); - RETURN(rc); + /* 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; } - proc_lustre_root = entry; + rc = jobid_cache_init(); + if (rc) { + kset_unregister(lustre_kset); + goto out; + } - rc = lprocfs_seq_create(proc_lustre_root, "devices", 0444, - &obd_device_list_fops, NULL); - if (rc < 0) { - CERROR("cannot create '/proc/fs/lustre/devices': rc = %d\n", - rc); - GOTO(out_proc, rc); + 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; } - RETURN(rc); + 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; + } -out_proc: - lprocfs_remove(&proc_lustre_root); + 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); } int class_procfs_clean(void) { - ENTRY; - if (proc_lustre_root) { - lprocfs_remove(&proc_lustre_root); - } - RETURN(0); + ENTRY; + + debugfs_remove_recursive(debugfs_lustre_root); + + 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); }