Whamcloud - gitweb
LU-16974 utils: make bandwidth options consistent
[fs/lustre-release.git] / lustre / lmv / lproc_lmv.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 /*
4  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
5  * Use is subject to license terms.
6  *
7  * Copyright (c) 2012, 2017, Intel Corporation.
8  */
9
10 /*
11  * This file is part of Lustre, http://www.lustre.org/
12  */
13
14 #define DEBUG_SUBSYSTEM S_CLASS
15
16 #include <linux/seq_file.h>
17 #include <linux/statfs.h>
18 #include <lprocfs_status.h>
19 #include <obd_class.h>
20
21 #include "lmv_internal.h"
22
23 static ssize_t numobd_show(struct kobject *kobj, struct attribute *attr,
24                            char *buf)
25 {
26         struct obd_device *obd = container_of(kobj, struct obd_device,
27                                               obd_kset.kobj);
28
29         return scnprintf(buf, PAGE_SIZE, "%u\n", obd->u.lmv.lmv_mdt_count);
30 }
31 LUSTRE_RO_ATTR(numobd);
32
33 static ssize_t activeobd_show(struct kobject *kobj, struct attribute *attr,
34                               char *buf)
35 {
36         struct obd_device *obd = container_of(kobj, struct obd_device,
37                                               obd_kset.kobj);
38
39         return scnprintf(buf, PAGE_SIZE, "%u\n",
40                 obd->u.lmv.lmv_mdt_descs.ltd_lmv_desc.ld_active_tgt_count);
41 }
42 LUSTRE_RO_ATTR(activeobd);
43
44 static ssize_t desc_uuid_show(struct kobject *kobj, struct attribute *attr,
45                               char *buf)
46 {
47         struct obd_device *obd = container_of(kobj, struct obd_device,
48                                               obd_kset.kobj);
49
50         return scnprintf(buf, PAGE_SIZE, "%s\n",
51                         obd->u.lmv.lmv_mdt_descs.ltd_lmv_desc.ld_uuid.uuid);
52 }
53 LUSTRE_RO_ATTR(desc_uuid);
54
55 static ssize_t qos_maxage_show(struct kobject *kobj,
56                                struct attribute *attr,
57                                char *buf)
58 {
59         struct obd_device *obd = container_of(kobj, struct obd_device,
60                                               obd_kset.kobj);
61
62         return scnprintf(buf, PAGE_SIZE, "%u\n",
63                         obd->u.lmv.lmv_mdt_descs.ltd_lmv_desc.ld_qos_maxage);
64 }
65
66 static ssize_t qos_maxage_store(struct kobject *kobj,
67                                 struct attribute *attr,
68                                 const char *buffer,
69                                 size_t count)
70 {
71         struct obd_device *obd = container_of(kobj, struct obd_device,
72                                               obd_kset.kobj);
73         unsigned int val;
74         int rc;
75
76         rc = kstrtouint(buffer, 0, &val);
77         if (rc)
78                 return rc;
79
80         obd->u.lmv.lmv_mdt_descs.ltd_lmv_desc.ld_qos_maxage = val;
81
82         return count;
83 }
84 LUSTRE_RW_ATTR(qos_maxage);
85
86 static ssize_t qos_prio_free_show(struct kobject *kobj,
87                                   struct attribute *attr,
88                                   char *buf)
89 {
90         struct obd_device *obd = container_of(kobj, struct obd_device,
91                                               obd_kset.kobj);
92
93         return scnprintf(buf, PAGE_SIZE, "%u%%\n",
94                         (obd->u.lmv.lmv_qos.lq_prio_free * 100 + 255) >> 8);
95 }
96
97 static ssize_t qos_prio_free_store(struct kobject *kobj,
98                                    struct attribute *attr,
99                                    const char *buffer,
100                                    size_t count)
101 {
102         struct obd_device *obd = container_of(kobj, struct obd_device,
103                                               obd_kset.kobj);
104         struct lmv_obd *lmv = &obd->u.lmv;
105         char buf[6], *tmp;
106         unsigned int val;
107         int rc;
108
109         /* "100%\n\0" should be largest string */
110         if (count >= sizeof(buf))
111                 return -ERANGE;
112
113         strncpy(buf, buffer, sizeof(buf));
114         buf[sizeof(buf) - 1] = '\0';
115         tmp = strchr(buf, '%');
116         if (tmp)
117                 *tmp = '\0';
118
119         rc = kstrtouint(buf, 0, &val);
120         if (rc)
121                 return rc;
122
123         if (val > 100)
124                 return -EINVAL;
125
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);
129
130         return count;
131 }
132 LUSTRE_RW_ATTR(qos_prio_free);
133
134 static ssize_t qos_threshold_rr_show(struct kobject *kobj,
135                                      struct attribute *attr,
136                                      char *buf)
137 {
138         struct obd_device *obd = container_of(kobj, struct obd_device,
139                                               obd_kset.kobj);
140
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);
144 }
145
146 static ssize_t qos_threshold_rr_store(struct kobject *kobj,
147                                       struct attribute *attr,
148                                       const char *buffer,
149                                       size_t count)
150 {
151         struct obd_device *obd = container_of(kobj, struct obd_device,
152                                               obd_kset.kobj);
153         struct lmv_obd *lmv = &obd->u.lmv;
154         char buf[6], *tmp;
155         unsigned int val;
156         int rc;
157
158         /* "100%\n\0" should be largest string */
159         if (count >= sizeof(buf))
160                 return -ERANGE;
161
162         strncpy(buf, buffer, sizeof(buf));
163         buf[sizeof(buf) - 1] = '\0';
164         tmp = strchr(buf, '%');
165         if (tmp)
166                 *tmp = '\0';
167
168         rc = kstrtouint(buf, 0, &val);
169         if (rc)
170                 return rc;
171
172         if (val > 100)
173                 return -EINVAL;
174
175         lmv->lmv_qos.lq_threshold_rr = (val * QOS_THRESHOLD_MAX) / 100;
176         set_bit(LQ_DIRTY, &lmv->lmv_qos.lq_flags);
177
178         return count;
179 }
180 LUSTRE_RW_ATTR(qos_threshold_rr);
181
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.
186  */
187 static int qos_exclude_prefixes_seq_show(struct seq_file *m, void *v)
188 {
189         struct obd_device *obd = m->private;
190         struct lmv_obd *lmv = &obd->u.lmv;
191         struct qos_exclude_prefix *prefix;
192
193 restart:
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);
199                         kvfree(m->buf);
200                         m->count = 0;
201                         m->buf = kvmalloc(m->size <<= 1, GFP_KERNEL_ACCOUNT);
202                         if (!m->buf)
203                                 return -ENOMEM;
204                         goto restart;
205                 }
206         }
207         spin_unlock(&lmv->lmv_lock);
208
209         return 0;
210 }
211
212 static ssize_t qos_exclude_prefixes_seq_write(struct file *file,
213                                               const char __user *buffer,
214                                               size_t count, loff_t *off)
215 {
216         struct obd_device *obd;
217         struct lmv_obd *lmv;
218         char *buf;
219         char op = 0;
220         char *p;
221         char *name;
222         char namebuf[NAME_MAX + 1];
223         struct qos_exclude_prefix *prefix;
224         struct qos_exclude_prefix *tmp;
225         int len;
226         bool pruned = false;
227         int rc;
228
229         /* one extra char to ensure buf ends with '\0' */
230         OBD_ALLOC(buf, count + 1);
231         if (!buf)
232                 return -ENOMEM;
233         if (copy_from_user(buf, buffer, count)) {
234                 OBD_FREE(buf, count + 1);
235                 return -EFAULT;
236         }
237
238         obd = ((struct seq_file *)file->private_data)->private;
239         lmv = &obd->u.lmv;
240         p = buf;
241         while (p) {
242                 while (*p == ':')
243                         p++;
244                 if (*p == '\0')
245                         break;
246                 if (*p == '+' || *p == '-')
247                         op = *p++;
248
249                 name = p;
250                 p = strchr(name, ':');
251                 if (p)
252                         len = p - name;
253                 else
254                         len = strlen(name);
255                 if (!len)
256                         break;
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);
261                         return -ERANGE;
262                 }
263
264                 switch (op) {
265                 default:
266                         if (!pruned) {
267                                 spin_lock(&lmv->lmv_lock);
268                                 list_for_each_entry_safe(prefix, tmp,
269                                                 &lmv->lmv_qos_exclude_list,
270                                                 qep_list) {
271                                         list_del(&prefix->qep_list);
272                                         rhashtable_remove_fast(
273                                                 &lmv->lmv_qos_exclude_hash,
274                                                 &prefix->qep_hash,
275                                                 qos_exclude_hash_params);
276                                         kfree(prefix);
277                                 }
278                                 spin_unlock(&lmv->lmv_lock);
279                                 pruned = true;
280                         }
281                         fallthrough;
282                 case '+':
283                         prefix = kmalloc(sizeof(*prefix), __GFP_ZERO);
284                         if (!prefix) {
285                                 OBD_FREE(buf, count + 1);
286                                 return -ENOMEM;
287                         }
288                         strncpy(prefix->qep_name, name, len);
289                         rc = rhashtable_lookup_insert_fast(
290                                                 &lmv->lmv_qos_exclude_hash,
291                                                 &prefix->qep_hash,
292                                                 qos_exclude_hash_params);
293                         if (!rc) {
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);
298                         } else {
299                                 kfree(prefix);
300                         }
301                         break;
302                 case '-':
303                         strncpy(namebuf, name, len);
304                         namebuf[len] = '\0';
305                         prefix = rhashtable_lookup(&lmv->lmv_qos_exclude_hash,
306                                                    namebuf,
307                                                    qos_exclude_hash_params);
308                         if (prefix) {
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,
314                                                 &prefix->qep_hash,
315                                                 qos_exclude_hash_params);
316                                 kfree(prefix);
317                         }
318                         break;
319                 }
320         }
321
322         OBD_FREE(buf, count + 1);
323         return count;
324 }
325 LDEBUGFS_SEQ_FOPS(qos_exclude_prefixes);
326
327 static struct ldebugfs_vars ldebugfs_lmv_obd_vars[] = {
328         { .name =       "qos_exclude_prefixes",
329           .fops =       &qos_exclude_prefixes_fops },
330         { NULL }
331 };
332
333 static void *lmv_tgt_seq_start(struct seq_file *p, loff_t *pos)
334 {
335         struct obd_device *obd = p->private;
336         struct lmv_obd *lmv = &obd->u.lmv;
337         struct lu_tgt_desc *tgt;
338
339         while (*pos < lmv->lmv_mdt_descs.ltd_tgts_size) {
340                 tgt = lmv_tgt(lmv, (__u32)*pos);
341                 if (tgt)
342                         return tgt;
343
344                 ++*pos;
345         }
346
347         return NULL;
348 }
349
350 static void lmv_tgt_seq_stop(struct seq_file *p, void *v)
351 {
352 }
353
354 static void *lmv_tgt_seq_next(struct seq_file *p, void *v, loff_t *pos)
355 {
356         struct obd_device *obd = p->private;
357         struct lmv_obd *lmv = &obd->u.lmv;
358         struct lu_tgt_desc *tgt;
359
360         ++*pos;
361         while (*pos < lmv->lmv_mdt_descs.ltd_tgts_size) {
362                 tgt = lmv_tgt(lmv, (__u32)*pos);
363                 if (tgt)
364                         return tgt;
365
366                 ++*pos;
367         }
368
369         return NULL;
370 }
371
372 static int lmv_tgt_seq_show(struct seq_file *p, void *v)
373 {
374         struct lmv_tgt_desc     *tgt = v;
375
376         if (!tgt)
377                 return 0;
378
379         seq_printf(p, "%u: %s %sACTIVE\n",
380                    tgt->ltd_index, tgt->ltd_uuid.uuid,
381                    tgt->ltd_active ? "" : "IN");
382         return 0;
383 }
384
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,
390 };
391
392 static int lmv_target_seq_open(struct inode *inode, struct file *file)
393 {
394         struct seq_file         *seq;
395         int                     rc;
396
397         rc = seq_open(file, &lmv_tgt_sops);
398         if (rc)
399                 return rc;
400
401         seq = file->private_data;
402         seq->private = inode->i_private;
403         return 0;
404 }
405
406 static const struct file_operations lmv_debugfs_target_fops = {
407         .owner          = THIS_MODULE,
408         .open           = lmv_target_seq_open,
409         .read           = seq_read,
410         .llseek         = seq_lseek,
411         .release        = seq_release,
412 };
413
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,
421         NULL,
422 };
423
424 KOBJ_ATTRIBUTE_GROUPS(lmv); /* creates lmv_groups */
425
426 int lmv_tunables_init(struct obd_device *obd)
427 {
428         int rc;
429
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);
433         if (rc)
434                 goto out_failed;
435 #ifdef CONFIG_PROC_FS
436         rc = lprocfs_alloc_md_stats(obd, 0);
437         if (rc) {
438                 lprocfs_obd_cleanup(obd);
439                 goto out_failed;
440         }
441 #endif /* CONFIG_PROC_FS */
442         debugfs_create_file("target_obd", 0444, obd->obd_debugfs_entry,
443                             obd, &lmv_debugfs_target_fops);
444 out_failed:
445         return rc;
446 }