X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Flod%2Flproc_lod.c;h=1ca3f5c61ad15bdf1effc613e2d847065e399633;hp=e168a43d2e9b1903aa31a129fac94e08c6293f04;hb=d5d0ff24a84f64e5196341f5ce946952d7fff8b7;hpb=a7369bcd860af61a073cb2424139e3acccdcb203;ds=sidebyside diff --git a/lustre/lod/lproc_lod.c b/lustre/lod/lproc_lod.c index e168a43..1ca3f5c 100644 --- a/lustre/lod/lproc_lod.c +++ b/lustre/lod/lproc_lod.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 2008 Sun Microsystems, Inc. All rights reserved * Use is subject to license terms. * - * Copyright (c) 2012, Intel Corporation. + * Copyright (c) 2012, 2017, Intel Corporation. */ /* * This file is part of Lustre, http://www.lustre.org/ @@ -39,433 +35,1002 @@ #include #include #include "lod_internal.h" -#include +#include + +/* + * Notice, all the functions below (except for lod_procfs_init() and + * lod_procfs_fini()) are not supposed to be used directly. They are + * called by Linux kernel's procfs. + */ + +#ifdef CONFIG_PROC_FS + +static ssize_t dom_stripesize_show(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + + return snprintf(buf, PAGE_SIZE, "%u\n", + lod->lod_dom_stripesize_max_kb << 10); +} + +static inline int dom_stripesize_max_kb_update(struct lod_device *lod, + __u64 val) +{ + /* 1GB is the limit */ + if (val > (1ULL << 20)) + return -ERANGE; + + if (val > 0) { + if (val < LOD_DOM_MIN_SIZE_KB) { + LCONSOLE_INFO("Increasing provided stripe size to a minimum value %u\n", + LOD_DOM_MIN_SIZE_KB); + val = LOD_DOM_MIN_SIZE_KB; + } else if (val & (LOD_DOM_MIN_SIZE_KB - 1)) { + val &= ~(LOD_DOM_MIN_SIZE_KB - 1); + LCONSOLE_WARN("Changing provided stripe size to %llu (a multiple of minimum %u)\n", + val, LOD_DOM_MIN_SIZE_KB); + } + } + spin_lock(&lod->lod_lsfs_lock); + lod->lod_dom_stripesize_max_kb = val; + lod_dom_stripesize_recalc(lod); + spin_unlock(&lod->lod_lsfs_lock); + return 0; +} + +static ssize_t dom_stripesize_store(struct kobject *kobj, + struct attribute *attr, + const char *buffer, size_t count) +{ + struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + u64 val; + int rc; -#ifdef LPROCFS -static int lod_rd_stripesize(char *page, char **start, off_t off, int count, - int *eof, void *data) + rc = sysfs_memparse(buffer, count, &val, "B"); + if (rc < 0) + return rc; + + rc = dom_stripesize_max_kb_update(lod, val >> 10); + if (rc) + return rc; + return count; +} + +/* Old attribute name is still supported */ +LUSTRE_RW_ATTR(dom_stripesize); + +/** + * Show DoM maximum allowed stripe size. + */ +static ssize_t dom_stripesize_max_kb_show(struct kobject *kobj, + struct attribute *attr, + char *buf) { - struct obd_device *dev = (struct obd_device *)data; - struct lod_device *lod; + struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); - LASSERT(dev != NULL); - lod = lu2lod_dev(dev->obd_lu_dev); - *eof = 1; - return snprintf(page, count, LPU64"\n", - lod->lod_desc.ld_default_stripe_size); + return snprintf(buf, PAGE_SIZE, "%u\n", + lod->lod_dom_stripesize_max_kb); } -static int lod_wr_stripesize(struct file *file, const char *buffer, - unsigned long count, void *data) +/** + * Set DoM maximum allowed stripe size. + */ +static ssize_t dom_stripesize_max_kb_store(struct kobject *kobj, + struct attribute *attr, + const char *buffer, size_t count) { - struct obd_device *dev = (struct obd_device *)data; - struct lod_device *lod; - __u64 val; + struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + u64 val; int rc; - LASSERT(dev != NULL); - lod = lu2lod_dev(dev->obd_lu_dev); - rc = lprocfs_write_u64_helper(buffer, count, &val); + rc = sysfs_memparse(buffer, count, &val, "KiB"); + if (rc < 0) + return rc; + + rc = dom_stripesize_max_kb_update(lod, val >> 10); if (rc) return rc; + return count; +} +LUSTRE_RW_ATTR(dom_stripesize_max_kb); + +/** + * Show DoM default stripe size. + */ +static ssize_t dom_stripesize_cur_kb_show(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + + return snprintf(buf, PAGE_SIZE, "%u\n", lod->lod_dom_stripesize_cur_kb); +} + +LUSTRE_RO_ATTR(dom_stripesize_cur_kb); + +/** + * Show DoM threshold. + */ +static ssize_t dom_threshold_free_mb_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + + return snprintf(buf, PAGE_SIZE, "%llu\n", + lod->lod_dom_threshold_free_mb); +} + +/** + * Set DoM default stripe size. + */ +static ssize_t dom_threshold_free_mb_store(struct kobject *kobj, + struct attribute *attr, + const char *buffer, size_t count) +{ + struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + u64 val; + int rc; + char *pct; + + pct = strnchr(buffer, count, '%'); + if (pct) { + rc = string_to_size(&val, buffer, pct - buffer); + if (rc < 0) + return rc; + val = mult_frac(lod->lod_lsfs_total_mb, + min_t(unsigned int, val, 100), 100); + } else { + rc = sysfs_memparse(buffer, count, &val, "MiB"); + if (rc < 0) + return rc; + val >>= 20; + } + + spin_lock(&lod->lod_lsfs_lock); + lod->lod_dom_threshold_free_mb = val; + lod_dom_stripesize_recalc(lod); + spin_unlock(&lod->lod_lsfs_lock); + + return count; +} + +LUSTRE_RW_ATTR(dom_threshold_free_mb); + +static ssize_t stripesize_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct dt_device *dt = container_of(kobj, struct dt_device, + dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + + return snprintf(buf, PAGE_SIZE, "%llu\n", + lod->lod_ost_descs.ltd_lov_desc.ld_default_stripe_size); +} + +static ssize_t stripesize_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count) +{ + struct dt_device *dt = container_of(kobj, struct dt_device, + dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + u64 val; + int rc; + + rc = sysfs_memparse(buffer, count, &val, "B"); + if (rc < 0) + return rc; lod_fix_desc_stripe_size(&val); - lod->lod_desc.ld_default_stripe_size = val; + lod->lod_ost_descs.ltd_lov_desc.ld_default_stripe_size = val; + return count; } -static int lod_rd_stripeoffset(char *page, char **start, off_t off, int count, - int *eof, void *data) +LUSTRE_RW_ATTR(stripesize); + +/** + * Show default stripe offset. + */ +static ssize_t stripeoffset_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - struct obd_device *dev = (struct obd_device *)data; - struct lod_device *lod; + struct dt_device *dt = container_of(kobj, struct dt_device, + dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); - LASSERT(dev != NULL); - lod = lu2lod_dev(dev->obd_lu_dev); - *eof = 1; - return snprintf(page, count, LPU64"\n", - lod->lod_desc.ld_default_stripe_offset); + return snprintf(buf, PAGE_SIZE, "%lld\n", + lod->lod_ost_descs.ltd_lov_desc.ld_default_stripe_offset); } -static int lod_wr_stripeoffset(struct file *file, const char *buffer, - unsigned long count, void *data) +/** + * Set default stripe offset. + * + * Usually contains -1 allowing Lustre to balance objects among OST + * otherwise may cause severe OST imbalance. + */ +static ssize_t stripeoffset_store(struct kobject *kobj, + struct attribute *attr, + const char *buffer, size_t count) { - struct obd_device *dev = (struct obd_device *)data; - struct lod_device *lod; - __u64 val; + struct dt_device *dt = container_of(kobj, struct dt_device, + dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + long val; int rc; - LASSERT(dev != NULL); - lod = lu2lod_dev(dev->obd_lu_dev); - rc = lprocfs_write_u64_helper(buffer, count, &val); + rc = kstrtol(buffer, 0, &val); if (rc) return rc; - lod->lod_desc.ld_default_stripe_offset = val; + if (val < -1 || val > LOV_MAX_STRIPE_COUNT) + return -ERANGE; + + lod->lod_ost_descs.ltd_lov_desc.ld_default_stripe_offset = val; + return count; } -static int lod_rd_stripetype(char *page, char **start, off_t off, int count, - int *eof, void *data) +LUSTRE_RW_ATTR(stripeoffset); + +/** + * Show default striping pattern (LOV_PATTERN_*). + */ +static ssize_t __stripetype_show(struct kobject *kobj, struct attribute *attr, + char *buf, bool is_mdt) { - struct obd_device *dev = (struct obd_device *)data; - struct lod_device *lod; + struct dt_device *dt = container_of(kobj, struct dt_device, + dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + struct lu_tgt_descs *ltd = is_mdt ? &lod->lod_mdt_descs : + &lod->lod_ost_descs; - LASSERT(dev != NULL); - lod = lu2lod_dev(dev->obd_lu_dev); - *eof = 1; - return snprintf(page, count, "%u\n", lod->lod_desc.ld_pattern); + return snprintf(buf, PAGE_SIZE, "%u\n", ltd->ltd_lov_desc.ld_pattern); } -static int lod_wr_stripetype(struct file *file, const char *buffer, - unsigned long count, void *data) +static ssize_t mdt_stripetype_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - struct obd_device *dev = (struct obd_device *)data; - struct lod_device *lod; - int val, rc; + return __stripetype_show(kobj, attr, buf, true); +} - LASSERT(dev != NULL); - lod = lu2lod_dev(dev->obd_lu_dev); - rc = lprocfs_write_helper(buffer, count, &val); +static ssize_t stripetype_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + return __stripetype_show(kobj, attr, buf, false); +} + +/** + * Set default striping pattern (a number, not a human-readable string). + */ +static ssize_t __stripetype_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count, bool is_mdt) +{ + struct dt_device *dt = container_of(kobj, struct dt_device, + dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + struct lu_tgt_descs *ltd = is_mdt ? &lod->lod_mdt_descs : + &lod->lod_ost_descs; + u32 pattern; + int rc; + + rc = kstrtouint(buffer, 0, &pattern); if (rc) return rc; - lod_fix_desc_pattern(&val); - lod->lod_desc.ld_pattern = val; + if (is_mdt) + lod_fix_lmv_desc_pattern(&pattern); + else + lod_fix_desc_pattern(&pattern); + + ltd->ltd_lov_desc.ld_pattern = pattern; + return count; } -static int lod_rd_stripecount(char *page, char **start, off_t off, int count, - int *eof, void *data) +static ssize_t mdt_stripetype_store(struct kobject *kobj, + struct attribute *attr, const char *buffer, + size_t count) +{ + return __stripetype_store(kobj, attr, buffer, count, true); +} + +static ssize_t stripetype_store(struct kobject *kobj, + struct attribute *attr, const char *buffer, + size_t count) +{ + return __stripetype_store(kobj, attr, buffer, count, false); +} + +LUSTRE_RW_ATTR(mdt_stripetype); +LUSTRE_RW_ATTR(stripetype); + +/** + * Show default number of stripes. + */ +static ssize_t __stripecount_show(struct kobject *kobj, struct attribute *attr, + char *buf, bool is_mdt) { - struct obd_device *dev = (struct obd_device *)data; - struct lod_device *lod; + struct dt_device *dt = container_of(kobj, struct dt_device, + dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + struct lov_desc *desc = is_mdt ? &lod->lod_mdt_descs.ltd_lov_desc : + &lod->lod_ost_descs.ltd_lov_desc; + + return snprintf(buf, PAGE_SIZE, "%d\n", + (s16)(desc->ld_default_stripe_count + 1) - 1); +} - LASSERT(dev != NULL); - lod = lu2lod_dev(dev->obd_lu_dev); - *eof = 1; - return snprintf(page, count, "%d\n", - (__s16)(lod->lod_desc.ld_default_stripe_count + 1) - 1); +static ssize_t mdt_stripecount_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return __stripecount_show(kobj, attr, buf, true); } -static int lod_wr_stripecount(struct file *file, const char *buffer, - unsigned long count, void *data) +static ssize_t stripecount_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - struct obd_device *dev = (struct obd_device *)data; - struct lod_device *lod; - int val, rc; + return __stripecount_show(kobj, attr, buf, false); +} - LASSERT(dev != NULL); - lod = lu2lod_dev(dev->obd_lu_dev); - rc = lprocfs_write_helper(buffer, count, &val); +/** + * Set default number of stripes. + */ +static ssize_t __stripecount_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count, + bool is_mdt) +{ + struct dt_device *dt = container_of(kobj, struct dt_device, + dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + struct lu_tgt_descs *ltd = is_mdt ? &lod->lod_mdt_descs : + &lod->lod_ost_descs; + int stripe_count; + int rc; + + rc = kstrtoint(buffer, 0, &stripe_count); if (rc) return rc; - lod_fix_desc_stripe_count(&val); - lod->lod_desc.ld_default_stripe_count = val; + if (stripe_count < -1) + return -ERANGE; + + lod_fix_desc_stripe_count(&stripe_count); + ltd->ltd_lov_desc.ld_default_stripe_count = stripe_count; + return count; } -static int lod_rd_numobd(char *page, char **start, off_t off, int count, - int *eof, void *data) +static ssize_t mdt_stripecount_store(struct kobject *kobj, + struct attribute *attr, + const char *buffer, size_t count) { - struct obd_device *dev = (struct obd_device*)data; - struct lod_device *lod; + return __stripecount_store(kobj, attr, buffer, count, true); +} + +static ssize_t stripecount_store(struct kobject *kobj, + struct attribute *attr, + const char *buffer, size_t count) +{ + return __stripecount_store(kobj, attr, buffer, count, false); +} - LASSERT(dev != NULL); - lod = lu2lod_dev(dev->obd_lu_dev); - *eof = 1; - return snprintf(page, count, "%u\n", lod->lod_desc.ld_tgt_count); +LUSTRE_RW_ATTR(mdt_stripecount); +LUSTRE_RW_ATTR(stripecount); +/** + * Show number of targets. + */ +static ssize_t __numobd_show(struct kobject *kobj, struct attribute *attr, + char *buf, bool is_mdt) +{ + struct dt_device *dt = container_of(kobj, struct dt_device, + dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + struct lu_tgt_descs *ltd = is_mdt ? &lod->lod_mdt_descs : + &lod->lod_ost_descs; + + return snprintf(buf, PAGE_SIZE, "%u\n", ltd->ltd_lov_desc.ld_tgt_count); } -static int lod_rd_activeobd(char *page, char **start, off_t off, int count, - int *eof, void *data) +static ssize_t mdt_numobd_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - struct obd_device* dev = (struct obd_device*)data; - struct lod_device *lod; + return __numobd_show(kobj, attr, buf, true); +} - LASSERT(dev != NULL); - lod = lu2lod_dev(dev->obd_lu_dev); - *eof = 1; - return snprintf(page, count, "%u\n", - lod->lod_desc.ld_active_tgt_count); +static ssize_t numobd_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + return __numobd_show(kobj, attr, buf, false); } -static int lod_rd_desc_uuid(char *page, char **start, off_t off, int count, - int *eof, void *data) +LUSTRE_RO_ATTR(mdt_numobd); +LUSTRE_RO_ATTR(numobd); + +/** + * Show number of active targets. + */ +static ssize_t __activeobd_show(struct kobject *kobj, struct attribute *attr, + char *buf, bool is_mdt) { - struct obd_device *dev = (struct obd_device*) data; - struct lod_device *lod; + struct dt_device *dt = container_of(kobj, struct dt_device, + dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + struct lu_tgt_descs *ltd = is_mdt ? &lod->lod_mdt_descs : + &lod->lod_ost_descs; + + return snprintf(buf, PAGE_SIZE, "%u\n", + ltd->ltd_lov_desc.ld_active_tgt_count); +} - LASSERT(dev != NULL); - lod = lu2lod_dev(dev->obd_lu_dev); - *eof = 1; - return snprintf(page, count, "%s\n", lod->lod_desc.ld_uuid.uuid); +static ssize_t mdt_activeobd_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + return __activeobd_show(kobj, attr, buf, true); } -/* free priority (0-255): how badly user wants to choose empty osts */ -static int lod_rd_qos_priofree(char *page, char **start, off_t off, int count, - int *eof, void *data) +static ssize_t activeobd_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - struct obd_device *dev = (struct obd_device*) data; - struct lod_device *lod = lu2lod_dev(dev->obd_lu_dev); + return __activeobd_show(kobj, attr, buf, false); +} + +LUSTRE_RO_ATTR(mdt_activeobd); +LUSTRE_RO_ATTR(activeobd); + +/** + * Show UUID of LOD device. + */ +static ssize_t desc_uuid_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct dt_device *dt = container_of(kobj, struct dt_device, + dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); - LASSERT(lod != NULL); - *eof = 1; - return snprintf(page, count, "%d%%\n", - (lod->lod_qos.lq_prio_free * 100 + 255) >> 8); + return snprintf(buf, PAGE_SIZE, "%s\n", + lod->lod_ost_descs.ltd_lov_desc.ld_uuid.uuid); } +LUSTRE_RO_ATTR(desc_uuid); -static int lod_wr_qos_priofree(struct file *file, const char *buffer, - unsigned long count, void *data) +/** + * Show QoS priority parameter. + * + * The printed value is a percentage value (0-100%) indicating the priority + * of free space compared to performance. 0% means select OSTs equally + * regardless of their free space, 100% means select OSTs only by their free + * space even if it results in very imbalanced load on the OSTs. + */ +static ssize_t __qos_prio_free_show(struct kobject *kobj, + struct attribute *attr, char *buf, + bool is_mdt) { - struct obd_device *dev = (struct obd_device *)data; - struct lod_device *lod; - int val, rc; + struct dt_device *dt = container_of(kobj, struct dt_device, + dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + struct lu_tgt_descs *ltd = is_mdt ? &lod->lod_mdt_descs : + &lod->lod_ost_descs; + + return snprintf(buf, PAGE_SIZE, "%d%%\n", + (ltd->ltd_qos.lq_prio_free * 100 + 255) >> 8); +} - LASSERT(dev != NULL); - lod = lu2lod_dev(dev->obd_lu_dev); +static ssize_t mdt_qos_prio_free_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return __qos_prio_free_show(kobj, attr, buf, true); +} + +static ssize_t qos_prio_free_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return __qos_prio_free_show(kobj, attr, buf, false); +} + +/** + * Set QoS free space priority parameter. + * + * Set the relative priority of free OST space compared to OST load when OSTs + * are space imbalanced. See qos_priofree_show() for description of + * this parameter. See qos_threshold_rr_store() and lq_threshold_rr to + * determine what constitutes "space imbalanced" OSTs. + */ +static ssize_t __qos_prio_free_store(struct kobject *kobj, + struct attribute *attr, + const char *buffer, size_t count, + bool is_mdt) +{ + struct dt_device *dt = container_of(kobj, struct dt_device, + dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + struct lu_tgt_descs *ltd = is_mdt ? &lod->lod_mdt_descs : + &lod->lod_ost_descs; + unsigned int val; + int rc; - rc = lprocfs_write_helper(buffer, count, &val); + rc = kstrtouint(buffer, 0, &val); if (rc) return rc; if (val > 100) return -EINVAL; - lod->lod_qos.lq_prio_free = (val << 8) / 100; - lod->lod_qos.lq_dirty = 1; - lod->lod_qos.lq_reset = 1; + ltd->ltd_qos.lq_prio_free = (val << 8) / 100; + ltd->ltd_qos.lq_dirty = 1; + ltd->ltd_qos.lq_reset = 1; + return count; } -static int lod_rd_qos_thresholdrr(char *page, char **start, off_t off, - int count, int *eof, void *data) +static ssize_t mdt_qos_prio_free_store(struct kobject *kobj, + struct attribute *attr, + const char *buffer, size_t count) { - struct obd_device *dev = (struct obd_device*) data; - struct lod_device *lod; + return __qos_prio_free_store(kobj, attr, buffer, count, true); +} - LASSERT(dev != NULL); - lod = lu2lod_dev(dev->obd_lu_dev); - *eof = 1; - return snprintf(page, count, "%d%%\n", - (lod->lod_qos.lq_threshold_rr * 100 + 255) >> 8); +static ssize_t qos_prio_free_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count) +{ + return __qos_prio_free_store(kobj, attr, buffer, count, false); } -static int lod_wr_qos_thresholdrr(struct file *file, const char *buffer, - unsigned long count, void *data) +LUSTRE_RW_ATTR(mdt_qos_prio_free); +LUSTRE_RW_ATTR(qos_prio_free); + +/** + * Show threshold for "same space on all OSTs" rule. + */ +static ssize_t __qos_threshold_rr_show(struct kobject *kobj, + struct attribute *attr, char *buf, + bool is_mdt) { - struct obd_device *dev = (struct obd_device *)data; - struct lod_device *lod; - int val, rc; + struct dt_device *dt = container_of(kobj, struct dt_device, + dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + struct lu_tgt_descs *ltd = is_mdt ? &lod->lod_mdt_descs : + &lod->lod_ost_descs; + + return snprintf(buf, PAGE_SIZE, "%d%%\n", + (ltd->ltd_qos.lq_threshold_rr * 100 + 255) >> 8); +} - LASSERT(dev != NULL); - lod = lu2lod_dev(dev->obd_lu_dev); +static ssize_t mdt_qos_threshold_rr_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return __qos_threshold_rr_show(kobj, attr, buf, true); +} + +static ssize_t qos_threshold_rr_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return __qos_threshold_rr_show(kobj, attr, buf, false); +} - rc = lprocfs_write_helper(buffer, count, &val); +/** + * Set threshold for "same space on all OSTs" rule. + * + * This sets the maximum percentage difference of free space between the most + * full and most empty OST in the currently available OSTs. If this percentage + * is exceeded, use the QoS allocator to select OSTs based on their available + * space so that more full OSTs are chosen less often, otherwise use the + * round-robin allocator for efficiency and performance. + */ +static ssize_t __qos_threshold_rr_store(struct kobject *kobj, + struct attribute *attr, + const char *buffer, size_t count, + bool is_mdt) +{ + struct dt_device *dt = container_of(kobj, struct dt_device, + dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + struct lu_tgt_descs *ltd = is_mdt ? &lod->lod_mdt_descs : + &lod->lod_ost_descs; + char buf[6], *tmp; + unsigned int val; + int rc; + + /* "100%\n\0" should be largest string */ + if (count >= sizeof(buf)) + return -ERANGE; + + strncpy(buf, buffer, sizeof(buf)); + buf[sizeof(buf) - 1] = '\0'; + tmp = strchr(buf, '%'); + if (tmp) + *tmp = '\0'; + + rc = kstrtouint(buf, 0, &val); if (rc) return rc; - if (val > 100 || val < 0) + if (val > 100) return -EINVAL; + ltd->ltd_qos.lq_threshold_rr = (val << 8) / 100; + ltd->ltd_qos.lq_dirty = 1; - lod->lod_qos.lq_threshold_rr = (val << 8) / 100; - lod->lod_qos.lq_dirty = 1; return count; } -static int lod_rd_qos_maxage(char *page, char **start, off_t off, int count, - int *eof, void *data) +static ssize_t mdt_qos_threshold_rr_store(struct kobject *kobj, + struct attribute *attr, + const char *buffer, size_t count) +{ + return __qos_threshold_rr_store(kobj, attr, buffer, count, true); +} + +static ssize_t qos_threshold_rr_store(struct kobject *kobj, + struct attribute *attr, + const char *buffer, size_t count) +{ + return __qos_threshold_rr_store(kobj, attr, buffer, count, false); +} + +LUSTRE_RW_ATTR(mdt_qos_threshold_rr); +LUSTRE_RW_ATTR(qos_threshold_rr); + +/** + * Show expiration period used to refresh cached statfs data, which + * is used to implement QoS/RR striping allocation algorithm. + */ +static ssize_t __qos_maxage_show(struct kobject *kobj, struct attribute *attr, + char *buf, bool is_mdt) { - struct obd_device *dev = (struct obd_device*) data; - struct lod_device *lod; + struct dt_device *dt = container_of(kobj, struct dt_device, + dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + struct lu_tgt_descs *ltd = is_mdt ? &lod->lod_mdt_descs : + &lod->lod_ost_descs; + + return snprintf(buf, PAGE_SIZE, "%u Sec\n", + ltd->ltd_lov_desc.ld_qos_maxage); +} - LASSERT(dev != NULL); - lod = lu2lod_dev(dev->obd_lu_dev); - *eof = 1; - return snprintf(page, count, "%u Sec\n", lod->lod_desc.ld_qos_maxage); +static ssize_t mdt_qos_maxage_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + return __qos_maxage_show(kobj, attr, buf, true); } -static int lod_wr_qos_maxage(struct file *file, const char *buffer, - unsigned long count, void *data) +static ssize_t qos_maxage_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - struct obd_device *dev = (struct obd_device *)data; - struct lustre_cfg_bufs bufs; - struct lod_device *lod; - struct lu_device *next; - struct lustre_cfg *lcfg; - char str[32]; - int val, rc, i; + return __qos_maxage_show(kobj, attr, buf, true); +} - LASSERT(dev != NULL); - lod = lu2lod_dev(dev->obd_lu_dev); +/** + * Set expiration period used to refresh cached statfs data. + */ +static ssize_t __qos_maxage_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count, bool is_mdt) +{ + struct dt_device *dt = container_of(kobj, struct dt_device, + dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + struct lu_tgt_descs *ltd = is_mdt ? &lod->lod_mdt_descs : + &lod->lod_ost_descs; + struct lustre_cfg_bufs bufs; + struct lu_device *next; + struct lustre_cfg *lcfg; + char str[32]; + struct lu_tgt_desc *tgt; + int rc; + u32 val; - rc = lprocfs_write_helper(buffer, count, &val); + rc = kstrtouint(buffer, 0, &val); if (rc) return rc; if (val <= 0) return -EINVAL; - lod->lod_desc.ld_qos_maxage = val; + + ltd->ltd_lov_desc.ld_qos_maxage = val; /* * propogate the value down to OSPs */ lustre_cfg_bufs_reset(&bufs, NULL); - sprintf(str, "%smaxage=%d", PARAM_OSP, val); + snprintf(str, 32, "%smaxage=%u", PARAM_OSP, val); lustre_cfg_bufs_set_string(&bufs, 1, str); - lcfg = lustre_cfg_new(LCFG_PARAM, &bufs); - lod_getref(&lod->lod_ost_descs); - lod_foreach_ost(lod, i) { - next = &OST_TGT(lod,i)->ltd_ost->dd_lu_dev; + OBD_ALLOC(lcfg, lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen)); + if (lcfg == NULL) + return -ENOMEM; + lustre_cfg_init(lcfg, LCFG_PARAM, &bufs); + + lod_getref(ltd); + ltd_foreach_tgt(ltd, tgt) { + next = &tgt->ltd_tgt->dd_lu_dev; rc = next->ld_ops->ldo_process_config(NULL, next, lcfg); if (rc) - CERROR("can't set maxage on #%d: %d\n", i, rc); + CERROR("can't set maxage on #%d: %d\n", + tgt->ltd_index, rc); } - lod_putref(lod, &lod->lod_ost_descs); - lustre_cfg_free(lcfg); + lod_putref(lod, ltd); + OBD_FREE(lcfg, lustre_cfg_len(lcfg->lcfg_bufcount, lcfg->lcfg_buflens)); return count; } -static void *lod_osts_seq_start(struct seq_file *p, loff_t *pos) +static ssize_t mdt_qos_maxage_store(struct kobject *kobj, + struct attribute *attr, + const char *buffer, size_t count) +{ + return __qos_maxage_store(kobj, attr, buffer, count, true); +} + +static ssize_t qos_maxage_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count) { - struct obd_device *dev = p->private; - struct lod_device *lod; + return __qos_maxage_store(kobj, attr, buffer, count, false); +} - LASSERT(dev != NULL); - lod = lu2lod_dev(dev->obd_lu_dev); +LUSTRE_RW_ATTR(mdt_qos_maxage); +LUSTRE_RW_ATTR(qos_maxage); - lod_getref(&lod->lod_ost_descs); /* released in lod_osts_seq_stop */ - if (*pos >= lod->lod_ost_bitmap->size) +static void *lod_tgts_seq_start(struct seq_file *p, loff_t *pos, bool is_mdt) +{ + struct obd_device *obd = p->private; + struct lod_device *lod = lu2lod_dev(obd->obd_lu_dev); + struct lu_tgt_descs *ltd = is_mdt ? &lod->lod_mdt_descs : + &lod->lod_ost_descs; + + LASSERT(obd != NULL); + + lod_getref(ltd); /* released in lod_tgts_seq_stop */ + if (*pos >= ltd->ltd_tgts_size) return NULL; - *pos = find_next_bit(lod->lod_ost_bitmap->data, - lod->lod_ost_bitmap->size, *pos); - if (*pos < lod->lod_ost_bitmap->size) - return OST_TGT(lod,*pos); + *pos = find_next_bit(ltd->ltd_tgt_bitmap, + ltd->ltd_tgts_size, *pos); + if (*pos < ltd->ltd_tgts_size) + return LTD_TGT(ltd, *pos); else return NULL; } -static void lod_osts_seq_stop(struct seq_file *p, void *v) +static void *lod_mdts_seq_start(struct seq_file *p, loff_t *pos) { - struct obd_device *dev = p->private; - struct lod_device *lod; + return lod_tgts_seq_start(p, pos, true); +} - LASSERT(dev != NULL); - lod = lu2lod_dev(dev->obd_lu_dev); - lod_putref(lod, &lod->lod_ost_descs); +static void *lod_osts_seq_start(struct seq_file *p, loff_t *pos) +{ + return lod_tgts_seq_start(p, pos, false); } -static void *lod_osts_seq_next(struct seq_file *p, void *v, loff_t *pos) +static void lod_tgts_seq_stop(struct seq_file *p, void *v, bool is_mdt) { - struct obd_device *dev = p->private; - struct lod_device *lod = lu2lod_dev(dev->obd_lu_dev); + struct obd_device *obd = p->private; + struct lod_device *lod = lu2lod_dev(obd->obd_lu_dev); + struct lu_tgt_descs *ltd = is_mdt ? &lod->lod_mdt_descs : + &lod->lod_ost_descs; + + LASSERT(obd != NULL); + lod_putref(lod, ltd); +} - if (*pos >= lod->lod_ost_bitmap->size - 1) +static void lod_mdts_seq_stop(struct seq_file *p, void *v) +{ + lod_tgts_seq_stop(p, v, true); +} + +static void lod_osts_seq_stop(struct seq_file *p, void *v) +{ + lod_tgts_seq_stop(p, v, false); +} + +static void *lod_tgts_seq_next(struct seq_file *p, void *v, loff_t *pos, + bool is_mdt) +{ + struct obd_device *obd = p->private; + struct lod_device *lod = lu2lod_dev(obd->obd_lu_dev); + struct lu_tgt_descs *ltd = is_mdt ? &lod->lod_mdt_descs : + &lod->lod_ost_descs; + + (*pos)++; + if (*pos > ltd->ltd_tgts_size - 1) return NULL; - *pos = find_next_bit(lod->lod_ost_bitmap->data, - lod->lod_ost_bitmap->size, *pos + 1); - if (*pos < lod->lod_ost_bitmap->size) - return OST_TGT(lod,*pos); + *pos = find_next_bit(ltd->ltd_tgt_bitmap, + ltd->ltd_tgts_size, *pos); + if (*pos < ltd->ltd_tgts_size) + return LTD_TGT(ltd, *pos); else return NULL; } -static int lod_osts_seq_show(struct seq_file *p, void *v) +static void *lod_mdts_seq_next(struct seq_file *p, void *v, loff_t *pos) +{ + return lod_tgts_seq_next(p, v, pos, true); +} + +static void *lod_osts_seq_next(struct seq_file *p, void *v, loff_t *pos) +{ + return lod_tgts_seq_next(p, v, pos, false); +} + +/** + * Show active/inactive status for OST found by lod_osts_seq_next(). + * + * \param[in] m seq file + * \param[in] v unused for single entry + * + * \retval 0 on success + * \retval negative error code if failed + */ +static int lod_tgts_seq_show(struct seq_file *p, void *v) { - struct obd_device *obd = p->private; - struct lod_ost_desc *ost_desc = v; - struct lod_device *lod; - int idx, rc, active; - struct dt_device *next; - struct obd_statfs sfs; + struct obd_device *obd = p->private; + struct lu_tgt_desc *tgt = v; + struct dt_device *next; + int rc, active; LASSERT(obd->obd_lu_dev); - lod = lu2lod_dev(obd->obd_lu_dev); - idx = ost_desc->ltd_index; - next = OST_TGT(lod,idx)->ltd_ost; - if (next == NULL) + next = tgt->ltd_tgt; + if (!next) return -EINVAL; /* XXX: should be non-NULL env, but it's very expensive */ active = 1; - rc = dt_statfs(NULL, next, &sfs); + rc = dt_statfs(NULL, next, &tgt->ltd_statfs); if (rc == -ENOTCONN) { active = 0; rc = 0; } else if (rc) return rc; - return seq_printf(p, "%d: %s %sACTIVE\n", idx, - obd_uuid2str(&ost_desc->ltd_uuid), - active ? "" : "IN"); + seq_printf(p, "%d: %s %sACTIVE\n", tgt->ltd_index, + obd_uuid2str(&tgt->ltd_uuid), + active ? "" : "IN"); + return 0; } +static const struct seq_operations lod_mdts_sops = { + .start = lod_mdts_seq_start, + .stop = lod_mdts_seq_stop, + .next = lod_mdts_seq_next, + .show = lod_tgts_seq_show, +}; + static const struct seq_operations lod_osts_sops = { .start = lod_osts_seq_start, .stop = lod_osts_seq_stop, .next = lod_osts_seq_next, - .show = lod_osts_seq_show, + .show = lod_tgts_seq_show, }; +static int lod_mdts_seq_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + int rc; + + rc = seq_open(file, &lod_mdts_sops); + if (rc) + return rc; + + seq = file->private_data; + seq->private = PDE_DATA(inode); + return 0; +} + static int lod_osts_seq_open(struct inode *inode, struct file *file) { - struct proc_dir_entry *dp = PDE(inode); struct seq_file *seq; int rc; - LPROCFS_ENTRY_AND_CHECK(dp); rc = seq_open(file, &lod_osts_sops); - if (rc) { - LPROCFS_EXIT(); + if (rc) return rc; - } seq = file->private_data; - seq->private = dp->data; + seq->private = PDE_DATA(inode); return 0; } -static struct lprocfs_vars lprocfs_lod_obd_vars[] = { - { "uuid", lprocfs_rd_uuid, 0, 0 }, - { "stripesize", lod_rd_stripesize, lod_wr_stripesize, 0 }, - { "stripeoffset", lod_rd_stripeoffset, lod_wr_stripeoffset, 0 }, - { "stripecount", lod_rd_stripecount, lod_wr_stripecount, 0 }, - { "stripetype", lod_rd_stripetype, lod_wr_stripetype, 0 }, - { "numobd", lod_rd_numobd, 0, 0 }, - { "activeobd", lod_rd_activeobd, 0, 0 }, - { "desc_uuid", lod_rd_desc_uuid, 0, 0 }, - { "qos_prio_free",lod_rd_qos_priofree, lod_wr_qos_priofree, 0 }, - { "qos_threshold_rr", lod_rd_qos_thresholdrr, lod_wr_qos_thresholdrr, 0 }, - { "qos_maxage", lod_rd_qos_maxage, lod_wr_qos_maxage, 0 }, - { 0 } -}; +/** + * Show whether special failout mode for testing is enabled or not. + */ +static ssize_t lmv_failout_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct dt_device *dt = container_of(kobj, struct dt_device, + dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); -static struct lprocfs_vars lprocfs_lod_osd_vars[] = { - { "blocksize", lprocfs_dt_rd_blksize, 0, 0 }, - { "kbytestotal", lprocfs_dt_rd_kbytestotal, 0, 0 }, - { "kbytesfree", lprocfs_dt_rd_kbytesfree, 0, 0 }, - { "kbytesavail", lprocfs_dt_rd_kbytesavail, 0, 0 }, - { "filestotal", lprocfs_dt_rd_filestotal, 0, 0 }, - { "filesfree", lprocfs_dt_rd_filesfree, 0, 0 }, - { 0 } -}; + return snprintf(buf, PAGE_SIZE, "%d\n", lod->lod_lmv_failout ? 1 : 0); +} + +/** + * Enable/disable a special failout mode for testing. + * + * This determines whether the LMV will try to continue processing a striped + * directory even if it has a (partly) corrupted entry in the master directory, + * or if it will abort upon finding a corrupted slave directory entry. + */ +static ssize_t lmv_failout_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count) +{ + struct dt_device *dt = container_of(kobj, struct dt_device, + dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + bool val = 0; + int rc; + + rc = kstrtobool(buffer, &val); + if (rc) + return rc; -static struct lprocfs_vars lprocfs_lod_module_vars[] = { - { "num_refs", lprocfs_rd_numrefs, 0, 0 }, - { 0 } + lod->lod_lmv_failout = val; + + return count; +} +LUSTRE_RW_ATTR(lmv_failout); + +char *mdt_hash_name[] = { "none", + LMV_HASH_NAME_ALL_CHARS, + LMV_HASH_NAME_FNV_1A_64, + LMV_HASH_NAME_CRUSH, }; -void lprocfs_lod_init_vars(struct lprocfs_static_vars *lvars) +static ssize_t mdt_hash_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - lvars->module_vars = lprocfs_lod_module_vars; - lvars->obd_vars = lprocfs_lod_obd_vars; + struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + + return snprintf(buf, PAGE_SIZE, "%s\n", + mdt_hash_name[lod->lod_mdt_descs.ltd_lmv_desc.ld_pattern]); } +static ssize_t mdt_hash_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count) +{ + struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); + struct lod_device *lod = dt2lod_dev(dt); + char *hash; + int len; + int i; + + hash = kstrndup(buffer, count, GFP_KERNEL); + if (!hash) + return -ENOMEM; + + len = strcspn(hash, "\n "); + hash[len] = '\0'; + for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++) { + if (!strcmp(hash, mdt_hash_name[i])) { + lod->lod_mdt_descs.ltd_lmv_desc.ld_pattern = i; + kfree(hash); + return count; + } + } + kfree(hash); + + return -EINVAL; +} +LUSTRE_RW_ATTR(mdt_hash); + +static struct lprocfs_vars lprocfs_lod_obd_vars[] = { + { NULL } +}; + +static const struct file_operations lod_proc_mdt_fops = { + .owner = THIS_MODULE, + .open = lod_mdts_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = lprocfs_seq_release, +}; + static const struct file_operations lod_proc_target_fops = { .owner = THIS_MODULE, .open = lod_osts_seq_open, @@ -474,29 +1039,77 @@ static const struct file_operations lod_proc_target_fops = { .release = lprocfs_seq_release, }; +static struct attribute *lod_attrs[] = { + &lustre_attr_dom_stripesize.attr, + &lustre_attr_dom_stripesize_max_kb.attr, + &lustre_attr_dom_stripesize_cur_kb.attr, + &lustre_attr_dom_threshold_free_mb.attr, + &lustre_attr_stripesize.attr, + &lustre_attr_stripeoffset.attr, + &lustre_attr_stripecount.attr, + &lustre_attr_stripetype.attr, + &lustre_attr_activeobd.attr, + &lustre_attr_desc_uuid.attr, + &lustre_attr_lmv_failout.attr, + &lustre_attr_numobd.attr, + &lustre_attr_qos_maxage.attr, + &lustre_attr_qos_prio_free.attr, + &lustre_attr_qos_threshold_rr.attr, + &lustre_attr_mdt_stripecount.attr, + &lustre_attr_mdt_stripetype.attr, + &lustre_attr_mdt_activeobd.attr, + &lustre_attr_mdt_numobd.attr, + &lustre_attr_mdt_qos_maxage.attr, + &lustre_attr_mdt_qos_prio_free.attr, + &lustre_attr_mdt_qos_threshold_rr.attr, + &lustre_attr_mdt_hash.attr, + NULL, +}; + +/** + * Initialize procfs entries for LOD. + * + * \param[in] lod LOD device + * + * \retval 0 on success + * \retval negative error code if failed + */ int lod_procfs_init(struct lod_device *lod) { + struct ldebugfs_vars ldebugfs_obd_vars[] = { { NULL } }; struct obd_device *obd = lod2obd(lod); - struct lprocfs_static_vars lvars; - cfs_proc_dir_entry_t *lov_proc_dir; + struct obd_type *type; + struct kobject *lov; int rc; - lprocfs_lod_init_vars(&lvars); - rc = lprocfs_obd_setup(obd, lvars.obd_vars); + lod->lod_dt_dev.dd_ktype.default_attrs = lod_attrs; + rc = dt_tunables_init(&lod->lod_dt_dev, obd->obd_type, obd->obd_name, + ldebugfs_obd_vars); if (rc) { - CERROR("%s: cannot setup procfs entry: %d\n", + CERROR("%s: failed to setup DT tunables: %d\n", obd->obd_name, rc); RETURN(rc); } - rc = lprocfs_add_vars(obd->obd_proc_entry, lprocfs_lod_osd_vars, - &lod->lod_dt_dev); - if (rc) { - CERROR("%s: cannot setup procfs entry: %d\n", + obd->obd_vars = lprocfs_lod_obd_vars; + obd->obd_proc_entry = lprocfs_register(obd->obd_name, + obd->obd_type->typ_procroot, + obd->obd_vars, obd); + if (IS_ERR(obd->obd_proc_entry)) { + rc = PTR_ERR(obd->obd_proc_entry); + CERROR("%s: error %d setting up lprocfs\n", obd->obd_name, rc); GOTO(out, rc); } + rc = lprocfs_seq_create(obd->obd_proc_entry, "mdt_obd", + 0444, &lod_proc_mdt_fops, obd); + if (rc) { + CWARN("%s: Error adding the target_obd file %d\n", + obd->obd_name, rc); + GOTO(out, rc); + } + rc = lprocfs_seq_create(obd->obd_proc_entry, "target_obd", 0444, &lod_proc_target_fops, obd); if (rc) { @@ -516,36 +1129,73 @@ int lod_procfs_init(struct lod_device *lod) GOTO(out, rc); } - /* for compatibility we link old procfs's OSC entries to osp ones */ - lov_proc_dir = lprocfs_srch(proc_lustre_root, "lov"); - if (lov_proc_dir != NULL && strstr(obd->obd_name, "lov") != NULL) - lod->lod_symlink = lprocfs_add_symlink(obd->obd_name, - lov_proc_dir, - "../lod/%s", - obd->obd_name); + lov = kset_find_obj(lustre_kset, "lov"); + if (!lov) { + CERROR("%s: lov subsystem not found\n", obd->obd_name); + GOTO(out, rc = -ENODEV); + } + rc = sysfs_create_link(lov, &lod->lod_dt_dev.dd_kobj, + obd->obd_name); + if (rc) + CERROR("%s: failed to create LOV sysfs symlink\n", + obd->obd_name); + kobject_put(lov); + + lod->lod_debugfs = ldebugfs_add_symlink(obd->obd_name, "lov", + "../lod/%s", obd->obd_name); + if (!lod->lod_debugfs) + CERROR("%s: failed to create LOV debugfs symlink\n", + obd->obd_name); + + type = container_of(lov, struct obd_type, typ_kobj); + if (!type->typ_procroot) + RETURN(0); + + /* for compatibility we link old procfs's LOV entries to lod ones */ + lod->lod_symlink = lprocfs_add_symlink(obd->obd_name, + type->typ_procroot, + "../lod/%s", obd->obd_name); + if (lod->lod_symlink == NULL) + CERROR("cannot create LOV symlink for /proc/fs/lustre/lod/%s\n", + obd->obd_name); RETURN(0); out: - lprocfs_obd_cleanup(obd); + dt_tunables_fini(&lod->lod_dt_dev); return rc; } +/** + * Cleanup procfs entries registred for LOD. + * + * \param[in] lod LOD device + */ void lod_procfs_fini(struct lod_device *lod) { struct obd_device *obd = lod2obd(lod); + struct kobject *lov; - if (lod->lod_symlink != NULL) + if (lod->lod_symlink != NULL) { lprocfs_remove(&lod->lod_symlink); + lod->lod_symlink = NULL; + } - if (lod->lod_pool_proc_entry != NULL) { - lprocfs_remove(&lod->lod_pool_proc_entry); - lod->lod_pool_proc_entry = NULL; + lov = kset_find_obj(lustre_kset, "lov"); + if (lov) { + sysfs_remove_link(lov, obd->obd_name); + kobject_put(lov); } - lprocfs_obd_cleanup(obd); -} + debugfs_remove_recursive(lod->lod_debugfs); + + if (obd->obd_proc_entry) { + lprocfs_remove(&obd->obd_proc_entry); + obd->obd_proc_entry = NULL; + } -#endif /* LPROCFS */ + dt_tunables_fini(&lod->lod_dt_dev); +} +#endif /* CONFIG_PROC_FS */