1 // SPDX-License-Identifier: GPL-2.0
4 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
5 * Use is subject to license terms.
7 * Copyright (c) 2012, 2017, Intel Corporation.
11 * This file is part of Lustre, http://www.lustre.org/
14 #define DEBUG_SUBSYSTEM S_CLASS
16 #include <linux/seq_file.h>
17 #include <linux/statfs.h>
18 #include <lprocfs_status.h>
19 #include <obd_class.h>
21 #include "lmv_internal.h"
23 static ssize_t numobd_show(struct kobject *kobj, struct attribute *attr,
26 struct obd_device *obd = container_of(kobj, struct obd_device,
29 return scnprintf(buf, PAGE_SIZE, "%u\n", obd->u.lmv.lmv_mdt_count);
31 LUSTRE_RO_ATTR(numobd);
33 static ssize_t activeobd_show(struct kobject *kobj, struct attribute *attr,
36 struct obd_device *obd = container_of(kobj, struct obd_device,
39 return scnprintf(buf, PAGE_SIZE, "%u\n",
40 obd->u.lmv.lmv_mdt_descs.ltd_lmv_desc.ld_active_tgt_count);
42 LUSTRE_RO_ATTR(activeobd);
44 static ssize_t desc_uuid_show(struct kobject *kobj, struct attribute *attr,
47 struct obd_device *obd = container_of(kobj, struct obd_device,
50 return scnprintf(buf, PAGE_SIZE, "%s\n",
51 obd->u.lmv.lmv_mdt_descs.ltd_lmv_desc.ld_uuid.uuid);
53 LUSTRE_RO_ATTR(desc_uuid);
55 static ssize_t qos_maxage_show(struct kobject *kobj,
56 struct attribute *attr,
59 struct obd_device *obd = container_of(kobj, struct obd_device,
62 return scnprintf(buf, PAGE_SIZE, "%u\n",
63 obd->u.lmv.lmv_mdt_descs.ltd_lmv_desc.ld_qos_maxage);
66 static ssize_t qos_maxage_store(struct kobject *kobj,
67 struct attribute *attr,
71 struct obd_device *obd = container_of(kobj, struct obd_device,
76 rc = kstrtouint(buffer, 0, &val);
80 obd->u.lmv.lmv_mdt_descs.ltd_lmv_desc.ld_qos_maxage = val;
84 LUSTRE_RW_ATTR(qos_maxage);
86 static ssize_t qos_prio_free_show(struct kobject *kobj,
87 struct attribute *attr,
90 struct obd_device *obd = container_of(kobj, struct obd_device,
93 return scnprintf(buf, PAGE_SIZE, "%u%%\n",
94 (obd->u.lmv.lmv_qos.lq_prio_free * 100 + 255) >> 8);
97 static ssize_t qos_prio_free_store(struct kobject *kobj,
98 struct attribute *attr,
102 struct obd_device *obd = container_of(kobj, struct obd_device,
104 struct lmv_obd *lmv = &obd->u.lmv;
109 /* "100%\n\0" should be largest string */
110 if (count >= sizeof(buf))
113 strncpy(buf, buffer, sizeof(buf));
114 buf[sizeof(buf) - 1] = '\0';
115 tmp = strchr(buf, '%');
119 rc = kstrtouint(buf, 0, &val);
126 lmv->lmv_qos.lq_prio_free = (val << 8) / 100;
127 set_bit(LQ_DIRTY, &lmv->lmv_qos.lq_flags);
128 set_bit(LQ_RESET, &lmv->lmv_qos.lq_flags);
132 LUSTRE_RW_ATTR(qos_prio_free);
134 static ssize_t qos_threshold_rr_show(struct kobject *kobj,
135 struct attribute *attr,
138 struct obd_device *obd = container_of(kobj, struct obd_device,
141 return scnprintf(buf, PAGE_SIZE, "%u%%\n",
142 (obd->u.lmv.lmv_qos.lq_threshold_rr * 100 +
143 (QOS_THRESHOLD_MAX - 1)) / QOS_THRESHOLD_MAX);
146 static ssize_t qos_threshold_rr_store(struct kobject *kobj,
147 struct attribute *attr,
151 struct obd_device *obd = container_of(kobj, struct obd_device,
153 struct lmv_obd *lmv = &obd->u.lmv;
158 /* "100%\n\0" should be largest string */
159 if (count >= sizeof(buf))
162 strncpy(buf, buffer, sizeof(buf));
163 buf[sizeof(buf) - 1] = '\0';
164 tmp = strchr(buf, '%');
168 rc = kstrtouint(buf, 0, &val);
175 lmv->lmv_qos.lq_threshold_rr = (val * QOS_THRESHOLD_MAX) / 100;
176 set_bit(LQ_DIRTY, &lmv->lmv_qos.lq_flags);
180 LUSTRE_RW_ATTR(qos_threshold_rr);
182 /* directories with exclude prefixes will be created on the same MDT as its
183 * parent directory, the prefixes are set with the rule as shell environment
184 * PATH: ':' is used as separator for prefixes. And for convenience, '+/-' is
185 * used to add/remove prefixes.
187 static int qos_exclude_prefixes_seq_show(struct seq_file *m, void *v)
189 struct obd_device *obd = m->private;
190 struct lmv_obd *lmv = &obd->u.lmv;
191 struct qos_exclude_prefix *prefix;
194 spin_lock(&lmv->lmv_lock);
195 list_for_each_entry(prefix, &lmv->lmv_qos_exclude_list, qep_list) {
196 seq_printf(m, "%s\n", prefix->qep_name);
197 if (seq_has_overflowed(m)) {
198 spin_unlock(&lmv->lmv_lock);
201 m->buf = kvmalloc(m->size <<= 1, GFP_KERNEL_ACCOUNT);
207 spin_unlock(&lmv->lmv_lock);
212 static ssize_t qos_exclude_prefixes_seq_write(struct file *file,
213 const char __user *buffer,
214 size_t count, loff_t *off)
216 struct obd_device *obd;
222 char namebuf[NAME_MAX + 1];
223 struct qos_exclude_prefix *prefix;
224 struct qos_exclude_prefix *tmp;
229 /* one extra char to ensure buf ends with '\0' */
230 OBD_ALLOC(buf, count + 1);
233 if (copy_from_user(buf, buffer, count)) {
234 OBD_FREE(buf, count + 1);
238 obd = ((struct seq_file *)file->private_data)->private;
246 if (*p == '+' || *p == '-')
250 p = strchr(name, ':');
257 if (len > NAME_MAX) {
258 CERROR("%s: %s length exceeds NAME_MAX\n",
259 obd->obd_name, name);
260 OBD_FREE(buf, count + 1);
267 spin_lock(&lmv->lmv_lock);
268 list_for_each_entry_safe(prefix, tmp,
269 &lmv->lmv_qos_exclude_list,
271 list_del(&prefix->qep_list);
272 rhashtable_remove_fast(
273 &lmv->lmv_qos_exclude_hash,
275 qos_exclude_hash_params);
278 spin_unlock(&lmv->lmv_lock);
283 prefix = kmalloc(sizeof(*prefix), __GFP_ZERO);
285 OBD_FREE(buf, count + 1);
288 strncpy(prefix->qep_name, name, len);
289 rc = rhashtable_lookup_insert_fast(
290 &lmv->lmv_qos_exclude_hash,
292 qos_exclude_hash_params);
294 spin_lock(&lmv->lmv_lock);
295 list_add_tail(&prefix->qep_list,
296 &lmv->lmv_qos_exclude_list);
297 spin_unlock(&lmv->lmv_lock);
303 strncpy(namebuf, name, len);
305 prefix = rhashtable_lookup(&lmv->lmv_qos_exclude_hash,
307 qos_exclude_hash_params);
309 spin_lock(&lmv->lmv_lock);
310 list_del(&prefix->qep_list);
311 spin_unlock(&lmv->lmv_lock);
312 rhashtable_remove_fast(
313 &lmv->lmv_qos_exclude_hash,
315 qos_exclude_hash_params);
322 OBD_FREE(buf, count + 1);
325 LDEBUGFS_SEQ_FOPS(qos_exclude_prefixes);
327 static struct ldebugfs_vars ldebugfs_lmv_obd_vars[] = {
328 { .name = "qos_exclude_prefixes",
329 .fops = &qos_exclude_prefixes_fops },
333 static void *lmv_tgt_seq_start(struct seq_file *p, loff_t *pos)
335 struct obd_device *obd = p->private;
336 struct lmv_obd *lmv = &obd->u.lmv;
337 struct lu_tgt_desc *tgt;
339 while (*pos < lmv->lmv_mdt_descs.ltd_tgts_size) {
340 tgt = lmv_tgt(lmv, (__u32)*pos);
350 static void lmv_tgt_seq_stop(struct seq_file *p, void *v)
354 static void *lmv_tgt_seq_next(struct seq_file *p, void *v, loff_t *pos)
356 struct obd_device *obd = p->private;
357 struct lmv_obd *lmv = &obd->u.lmv;
358 struct lu_tgt_desc *tgt;
361 while (*pos < lmv->lmv_mdt_descs.ltd_tgts_size) {
362 tgt = lmv_tgt(lmv, (__u32)*pos);
372 static int lmv_tgt_seq_show(struct seq_file *p, void *v)
374 struct lmv_tgt_desc *tgt = v;
379 seq_printf(p, "%u: %s %sACTIVE\n",
380 tgt->ltd_index, tgt->ltd_uuid.uuid,
381 tgt->ltd_active ? "" : "IN");
385 static const struct seq_operations lmv_tgt_sops = {
386 .start = lmv_tgt_seq_start,
387 .stop = lmv_tgt_seq_stop,
388 .next = lmv_tgt_seq_next,
389 .show = lmv_tgt_seq_show,
392 static int lmv_target_seq_open(struct inode *inode, struct file *file)
394 struct seq_file *seq;
397 rc = seq_open(file, &lmv_tgt_sops);
401 seq = file->private_data;
402 seq->private = inode->i_private;
406 static const struct file_operations lmv_debugfs_target_fops = {
407 .owner = THIS_MODULE,
408 .open = lmv_target_seq_open,
411 .release = seq_release,
414 static struct attribute *lmv_attrs[] = {
415 &lustre_attr_activeobd.attr,
416 &lustre_attr_desc_uuid.attr,
417 &lustre_attr_numobd.attr,
418 &lustre_attr_qos_maxage.attr,
419 &lustre_attr_qos_prio_free.attr,
420 &lustre_attr_qos_threshold_rr.attr,
424 KOBJ_ATTRIBUTE_GROUPS(lmv); /* creates lmv_groups */
426 int lmv_tunables_init(struct obd_device *obd)
430 obd->obd_ktype.default_groups = KOBJ_ATTR_GROUPS(lmv);
431 obd->obd_debugfs_vars = ldebugfs_lmv_obd_vars;
432 rc = lprocfs_obd_setup(obd, false);
435 #ifdef CONFIG_PROC_FS
436 rc = lprocfs_alloc_md_stats(obd, 0);
438 lprocfs_obd_cleanup(obd);
441 #endif /* CONFIG_PROC_FS */
442 debugfs_create_file("target_obd", 0444, obd->obd_debugfs_entry,
443 obd, &lmv_debugfs_target_fops);