Whamcloud - gitweb
LU-9611 lod: allow -1 for default stripe count/offset
[fs/lustre-release.git] / lustre / lod / lproc_lod.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2012, 2016, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  */
32 #define DEBUG_SUBSYSTEM S_CLASS
33
34 #include <lprocfs_status.h>
35 #include <obd_class.h>
36 #include <linux/seq_file.h>
37 #include "lod_internal.h"
38 #include <uapi/linux/lustre_param.h>
39
40 /*
41  * Notice, all the functions below (except for lod_procfs_init() and
42  * lod_procfs_fini()) are not supposed to be used directly. They are
43  * called by Linux kernel's procfs.
44  */
45
46 #ifdef CONFIG_PROC_FS
47
48 /**
49  * Show default stripe size.
50  *
51  * \param[in] m         seq file
52  * \param[in] v         unused for single entry
53  *
54  * \retval 0            on success
55  * \retval negative     error code if failed
56  */
57 static int lod_stripesize_seq_show(struct seq_file *m, void *v)
58 {
59         struct obd_device *dev = m->private;
60         struct lod_device *lod;
61
62         LASSERT(dev != NULL);
63         lod  = lu2lod_dev(dev->obd_lu_dev);
64         seq_printf(m, "%llu\n",
65                    lod->lod_desc.ld_default_stripe_size);
66         return 0;
67 }
68
69 /**
70  * Set default stripe size.
71  *
72  * \param[in] file      proc file
73  * \param[in] buffer    string containing the maximum number of bytes stored in
74  *                      each object before moving to the next object in the
75  *                      layout (if any)
76  * \param[in] count     @buffer length
77  * \param[in] off       unused for single entry
78  *
79  * \retval @count       on success
80  * \retval negative     error code if failed
81  */
82 static ssize_t
83 lod_stripesize_seq_write(struct file *file, const char __user *buffer,
84                          size_t count, loff_t *off)
85 {
86         struct seq_file *m = file->private_data;
87         struct obd_device *dev = m->private;
88         struct lod_device *lod;
89         __s64 val;
90         int rc;
91
92         LASSERT(dev != NULL);
93         lod  = lu2lod_dev(dev->obd_lu_dev);
94         rc = lprocfs_str_with_units_to_s64(buffer, count, &val, '1');
95         if (rc)
96                 return rc;
97         if (val < 0)
98                 return -ERANGE;
99
100         lod_fix_desc_stripe_size(&val);
101         lod->lod_desc.ld_default_stripe_size = val;
102
103         return count;
104 }
105 LPROC_SEQ_FOPS(lod_stripesize);
106
107 /**
108  * Show default stripe offset.
109  *
110  * \param[in] m         seq file
111  * \param[in] v         unused for single entry
112  *
113  * \retval 0            on success
114  * \retval negative     error code if failed
115  */
116 static int lod_stripeoffset_seq_show(struct seq_file *m, void *v)
117 {
118         struct obd_device *dev = m->private;
119         struct lod_device *lod;
120
121         LASSERT(dev != NULL);
122         lod  = lu2lod_dev(dev->obd_lu_dev);
123         seq_printf(m, "%llu\n",
124                    lod->lod_desc.ld_default_stripe_offset);
125         return 0;
126 }
127
128 /**
129  * Set default stripe offset.
130  *
131  * Usually contains -1 allowing Lustre to balance objects among OST
132  * otherwise may cause severe OST imbalance.
133  *
134  * \param[in] file      proc file
135  * \param[in] buffer    string describing starting OST index for new files
136  * \param[in] count     @buffer length
137  * \param[in] off       unused for single entry
138  *
139  * \retval @count       on success
140  * \retval negative     error code if failed
141  */
142 static ssize_t
143 lod_stripeoffset_seq_write(struct file *file, const char __user *buffer,
144                            size_t count, loff_t *off)
145 {
146         struct seq_file *m = file->private_data;
147         struct obd_device *dev = m->private;
148         struct lod_device *lod;
149         __s64 val;
150         int rc;
151
152         LASSERT(dev != NULL);
153         lod  = lu2lod_dev(dev->obd_lu_dev);
154         rc = lprocfs_str_with_units_to_s64(buffer, count, &val, '1');
155         if (rc)
156                 return rc;
157         if (val < -1)
158                 return -ERANGE;
159
160         lod->lod_desc.ld_default_stripe_offset = val;
161
162         return count;
163 }
164 LPROC_SEQ_FOPS(lod_stripeoffset);
165
166 /**
167  * Show default striping pattern (LOV_PATTERN_*).
168  *
169  * \param[in] m         seq file
170  * \param[in] v         unused for single entry
171  *
172  * \retval 0            on success
173  * \retval negative     error code if failed
174  */
175 static int lod_stripetype_seq_show(struct seq_file *m, void *v)
176 {
177         struct obd_device *dev = m->private;
178         struct lod_device *lod;
179
180         LASSERT(dev != NULL);
181         lod  = lu2lod_dev(dev->obd_lu_dev);
182         seq_printf(m, "%u\n", lod->lod_desc.ld_pattern);
183         return 0;
184 }
185
186 /**
187  * Set default striping pattern (a number, not a human-readable string).
188  *
189  * \param[in] file      proc file
190  * \param[in] buffer    string containing the default striping pattern for new
191  *                      files. This is an integer LOV_PATTERN_* value
192  * \param[in] count     @buffer length
193  * \param[in] off       unused for single entry
194  *
195  * \retval @count       on success
196  * \retval negative     error code if failed
197  */
198 static ssize_t
199 lod_stripetype_seq_write(struct file *file, const char __user *buffer,
200                          size_t count, loff_t *off)
201 {
202         struct seq_file *m = file->private_data;
203         struct obd_device *dev = m->private;
204         struct lod_device *lod;
205         int rc;
206         __u32 pattern;
207         __s64 val;
208
209         LASSERT(dev != NULL);
210         lod  = lu2lod_dev(dev->obd_lu_dev);
211         rc = lprocfs_str_to_s64(buffer, count, &val);
212         if (rc)
213                 return rc;
214         if (val < 0)
215                 return -ERANGE;
216
217         pattern = val;
218         lod_fix_desc_pattern(&pattern);
219         lod->lod_desc.ld_pattern = pattern;
220
221         return count;
222 }
223 LPROC_SEQ_FOPS(lod_stripetype);
224
225 /**
226  * Show default number of stripes.
227  *
228  * \param[in] m         seq file
229  * \param[in] v         unused for single entry
230  *
231  * \retval 0            on success,
232  * \retval negative     error code if failed
233  */
234 static int lod_stripecount_seq_show(struct seq_file *m, void *v)
235 {
236         struct obd_device *dev = m->private;
237         struct lod_device *lod;
238
239         LASSERT(dev != NULL);
240         lod  = lu2lod_dev(dev->obd_lu_dev);
241         seq_printf(m, "%d\n",
242                    (__s16)(lod->lod_desc.ld_default_stripe_count + 1) - 1);
243         return 0;
244 }
245
246 /**
247  * Set default number of stripes.
248  *
249  * \param[in] file      proc file
250  * \param[in] buffer    string containing the default number of stripes
251  *                      for new files
252  * \param[in] count     @buffer length
253  * \param[in] off       unused for single entry
254  *
255  * \retval @count       on success
256  * \retval negative     error code otherwise
257  */
258 static ssize_t
259 lod_stripecount_seq_write(struct file *file, const char __user *buffer,
260                           size_t count, loff_t *off)
261 {
262         struct seq_file *m = file->private_data;
263         struct obd_device *dev = m->private;
264         struct lod_device *lod;
265         int rc;
266         __s64 val;
267         __u32 stripe_count;
268
269         LASSERT(dev != NULL);
270         lod  = lu2lod_dev(dev->obd_lu_dev);
271         rc = lprocfs_str_to_s64(buffer, count, &val);
272         if (rc)
273                 return rc;
274         if (val < -1)
275                 return -ERANGE;
276
277         stripe_count = val;
278         lod_fix_desc_stripe_count(&stripe_count);
279         lod->lod_desc.ld_default_stripe_count = stripe_count;
280
281         return count;
282 }
283 LPROC_SEQ_FOPS(lod_stripecount);
284
285 /**
286  * Show number of targets.
287  *
288  * \param[in] m         seq file
289  * \param[in] v         unused for single entry
290  *
291  * \retval 0            on success
292  * \retval negative     error code if failed
293  */
294 static int lod_numobd_seq_show(struct seq_file *m, void *v)
295 {
296         struct obd_device *dev = m->private;
297         struct lod_device *lod;
298
299         LASSERT(dev != NULL);
300         lod  = lu2lod_dev(dev->obd_lu_dev);
301         seq_printf(m, "%u\n", lod->lod_desc.ld_tgt_count);
302         return 0;
303 }
304 LPROC_SEQ_FOPS_RO(lod_numobd);
305
306 /**
307  * Show number of active targets.
308  *
309  * \param[in] m         seq file
310  * \param[in] v         unused for single entry
311  *
312  * \retval 0            on success
313  * \retval negative     error code if failed
314  */
315 static int lod_activeobd_seq_show(struct seq_file *m, void *v)
316 {
317         struct obd_device *dev = m->private;
318         struct lod_device *lod;
319
320         LASSERT(dev != NULL);
321         lod  = lu2lod_dev(dev->obd_lu_dev);
322         seq_printf(m, "%u\n", lod->lod_desc.ld_active_tgt_count);
323         return 0;
324 }
325 LPROC_SEQ_FOPS_RO(lod_activeobd);
326
327 /**
328  * Show UUID of LOD device.
329  *
330  * \param[in] m         seq file
331  * \param[in] v         unused for single entry
332  *
333  * \retval 0            on success
334  * \retval negative     error code if failed
335  */
336 static int lod_desc_uuid_seq_show(struct seq_file *m, void *v)
337 {
338         struct obd_device *dev = m->private;
339         struct lod_device *lod;
340
341         LASSERT(dev != NULL);
342         lod  = lu2lod_dev(dev->obd_lu_dev);
343         seq_printf(m, "%s\n", lod->lod_desc.ld_uuid.uuid);
344         return 0;
345 }
346 LPROC_SEQ_FOPS_RO(lod_desc_uuid);
347
348 /**
349  * Show QoS priority parameter.
350  *
351  * The printed value is a percentage value (0-100%) indicating the priority
352  * of free space compared to performance. 0% means select OSTs equally
353  * regardless of their free space, 100% means select OSTs only by their free
354  * space even if it results in very imbalanced load on the OSTs.
355  *
356  * \param[in] m         seq file
357  * \param[in] v         unused for single entry
358  *
359  * \retval 0            on success
360  * \retval negative     error code if failed
361  */
362 static int lod_qos_priofree_seq_show(struct seq_file *m, void *v)
363 {
364         struct obd_device *dev = m->private;
365         struct lod_device *lod = lu2lod_dev(dev->obd_lu_dev);
366
367         LASSERT(lod != NULL);
368         seq_printf(m, "%d%%\n",
369                    (lod->lod_qos.lq_prio_free * 100 + 255) >> 8);
370         return 0;
371 }
372
373 /**
374  * Set QoS free space priority parameter.
375  *
376  * Set the relative priority of free OST space compared to OST load when OSTs
377  * are space imbalanced.  See lod_qos_priofree_seq_show() for description of
378  * this parameter.  See lod_qos_thresholdrr_seq_write() and lq_threshold_rr to
379  * determine what constitutes "space imbalanced" OSTs.
380  *
381  * \param[in] file      proc file
382  * \param[in] buffer    string which contains the free space priority (0-100)
383  * \param[in] count     @buffer length
384  * \param[in] off       unused for single entry
385  *
386  * \retval @count       on success
387  * \retval negative     error code if failed
388  */
389 static ssize_t
390 lod_qos_priofree_seq_write(struct file *file, const char __user *buffer,
391                            size_t count, loff_t *off)
392 {
393         struct seq_file *m = file->private_data;
394         struct obd_device *dev = m->private;
395         struct lod_device *lod;
396         int rc;
397         __s64 val;
398
399         LASSERT(dev != NULL);
400         lod = lu2lod_dev(dev->obd_lu_dev);
401
402         rc = lprocfs_str_to_s64(buffer, count, &val);
403         if (rc)
404                 return rc;
405
406         if (val < 0 || val > 100)
407                 return -EINVAL;
408         lod->lod_qos.lq_prio_free = (val << 8) / 100;
409         lod->lod_qos.lq_dirty = 1;
410         lod->lod_qos.lq_reset = 1;
411
412         return count;
413 }
414 LPROC_SEQ_FOPS(lod_qos_priofree);
415
416 /**
417  * Show threshold for "same space on all OSTs" rule.
418  *
419  * \param[in] m         seq file
420  * \param[in] v         unused for single entry
421  *
422  * \retval 0            on success
423  * \retval negative     error code if failed
424  */
425 static int lod_qos_thresholdrr_seq_show(struct seq_file *m, void *v)
426 {
427         struct obd_device *dev = m->private;
428         struct lod_device *lod;
429
430         LASSERT(dev != NULL);
431         lod = lu2lod_dev(dev->obd_lu_dev);
432         seq_printf(m, "%d%%\n",
433                    (lod->lod_qos.lq_threshold_rr * 100 + 255) >> 8);
434         return 0;
435 }
436
437 /**
438  * Set threshold for "same space on all OSTs" rule.
439  *
440  * This sets the maximum percentage difference of free space between the most
441  * full and most empty OST in the currently available OSTs. If this percentage
442  * is exceeded, use the QoS allocator to select OSTs based on their available
443  * space so that more full OSTs are chosen less often, otherwise use the
444  * round-robin allocator for efficiency and performance.
445
446  * \param[in] file      proc file
447  * \param[in] buffer    string containing percentage difference of free space
448  * \param[in] count     @buffer length
449  * \param[in] off       unused for single entry
450  *
451  * \retval @count       on success
452  * \retval negative     error code if failed
453  */
454 static ssize_t
455 lod_qos_thresholdrr_seq_write(struct file *file, const char __user *buffer,
456                               size_t count, loff_t *off)
457 {
458         struct seq_file *m = file->private_data;
459         struct obd_device *dev = m->private;
460         struct lod_device *lod;
461         int rc;
462         __s64 val;
463
464         LASSERT(dev != NULL);
465         lod = lu2lod_dev(dev->obd_lu_dev);
466
467         rc = lprocfs_str_with_units_to_s64(buffer, count, &val, '%');
468         if (rc)
469                 return rc;
470
471         if (val > 100 || val < 0)
472                 return -EINVAL;
473
474         lod->lod_qos.lq_threshold_rr = (val << 8) / 100;
475         lod->lod_qos.lq_dirty = 1;
476
477         return count;
478 }
479 LPROC_SEQ_FOPS(lod_qos_thresholdrr);
480
481 /**
482  * Show expiration period used to refresh cached statfs data, which
483  * is used to implement QoS/RR striping allocation algorithm.
484  *
485  * \param[in] m         seq file
486  * \param[in] v         unused for single entry
487  *
488  * \retval 0            on success
489  * \retval negative     error code if failed
490  */
491 static int lod_qos_maxage_seq_show(struct seq_file *m, void *v)
492 {
493         struct obd_device *dev = m->private;
494         struct lod_device *lod;
495
496         LASSERT(dev != NULL);
497         lod = lu2lod_dev(dev->obd_lu_dev);
498         seq_printf(m, "%u Sec\n", lod->lod_desc.ld_qos_maxage);
499         return 0;
500 }
501
502 /**
503  * Set expiration period used to refresh cached statfs data.
504  *
505  * \param[in] file      proc file
506  * \param[in] buffer    string contains maximum age of statfs data in seconds
507  * \param[in] count     @buffer length
508  * \param[in] off       unused for single entry
509  *
510  * \retval @count       on success
511  * \retval negative     error code if failed
512  */
513 static ssize_t
514 lod_qos_maxage_seq_write(struct file *file, const char __user *buffer,
515                          size_t count, loff_t *off)
516 {
517         struct seq_file *m = file->private_data;
518         struct obd_device *dev = m->private;
519         struct lustre_cfg_bufs bufs;
520         struct lod_device *lod;
521         struct lu_device *next;
522         struct lustre_cfg *lcfg;
523         char str[32];
524         unsigned int i;
525         int rc;
526         __s64 val;
527
528         LASSERT(dev != NULL);
529         lod = lu2lod_dev(dev->obd_lu_dev);
530
531         rc = lprocfs_str_to_s64(buffer, count, &val);
532         if (rc)
533                 return rc;
534
535         if (val <= 0)
536                 return -EINVAL;
537         lod->lod_desc.ld_qos_maxage = val;
538
539         /*
540          * propogate the value down to OSPs
541          */
542         lustre_cfg_bufs_reset(&bufs, NULL);
543         snprintf(str, 32, "%smaxage=%u", PARAM_OSP, (__u32)val);
544         lustre_cfg_bufs_set_string(&bufs, 1, str);
545         OBD_ALLOC(lcfg, lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
546         if (lcfg == NULL)
547                 return -ENOMEM;
548         lustre_cfg_init(lcfg, LCFG_PARAM, &bufs);
549
550         lod_getref(&lod->lod_ost_descs);
551         lod_foreach_ost(lod, i) {
552                 next = &OST_TGT(lod,i)->ltd_ost->dd_lu_dev;
553                 rc = next->ld_ops->ldo_process_config(NULL, next, lcfg);
554                 if (rc)
555                         CERROR("can't set maxage on #%d: %d\n", i, rc);
556         }
557         lod_putref(lod, &lod->lod_ost_descs);
558         OBD_FREE(lcfg, lustre_cfg_len(lcfg->lcfg_bufcount, lcfg->lcfg_buflens));
559
560         return count;
561 }
562 LPROC_SEQ_FOPS(lod_qos_maxage);
563
564 static void *lod_osts_seq_start(struct seq_file *p, loff_t *pos)
565 {
566         struct obd_device *dev = p->private;
567         struct lod_device *lod;
568
569         LASSERT(dev != NULL);
570         lod = lu2lod_dev(dev->obd_lu_dev);
571
572         lod_getref(&lod->lod_ost_descs); /* released in lod_osts_seq_stop */
573         if (*pos >= lod->lod_ost_bitmap->size)
574                 return NULL;
575
576         *pos = find_next_bit(lod->lod_ost_bitmap->data,
577                                  lod->lod_ost_bitmap->size, *pos);
578         if (*pos < lod->lod_ost_bitmap->size)
579                 return OST_TGT(lod,*pos);
580         else
581                 return NULL;
582 }
583
584 static void lod_osts_seq_stop(struct seq_file *p, void *v)
585 {
586         struct obd_device *dev = p->private;
587         struct lod_device *lod;
588
589         LASSERT(dev != NULL);
590         lod = lu2lod_dev(dev->obd_lu_dev);
591         lod_putref(lod, &lod->lod_ost_descs);
592 }
593
594 static void *lod_osts_seq_next(struct seq_file *p, void *v, loff_t *pos)
595 {
596         struct obd_device *dev = p->private;
597         struct lod_device *lod = lu2lod_dev(dev->obd_lu_dev);
598
599         if (*pos >= lod->lod_ost_bitmap->size - 1)
600                 return NULL;
601
602         *pos = find_next_bit(lod->lod_ost_bitmap->data,
603                                  lod->lod_ost_bitmap->size, *pos + 1);
604         if (*pos < lod->lod_ost_bitmap->size)
605                 return OST_TGT(lod,*pos);
606         else
607                 return NULL;
608 }
609
610 /**
611  * Show active/inactive status for OST found by lod_osts_seq_next().
612  *
613  * \param[in] m         seq file
614  * \param[in] v         unused for single entry
615  *
616  * \retval 0            on success
617  * \retval negative     error code if failed
618  */
619 static int lod_osts_seq_show(struct seq_file *p, void *v)
620 {
621         struct obd_device   *obd = p->private;
622         struct lod_ost_desc *ost_desc = v;
623         struct lod_device   *lod;
624         int                  idx, rc, active;
625         struct dt_device    *next;
626         struct obd_statfs    sfs;
627
628         LASSERT(obd->obd_lu_dev);
629         lod = lu2lod_dev(obd->obd_lu_dev);
630
631         idx = ost_desc->ltd_index;
632         next = OST_TGT(lod,idx)->ltd_ost;
633         if (next == NULL)
634                 return -EINVAL;
635
636         /* XXX: should be non-NULL env, but it's very expensive */
637         active = 1;
638         rc = dt_statfs(NULL, next, &sfs);
639         if (rc == -ENOTCONN) {
640                 active = 0;
641                 rc = 0;
642         } else if (rc)
643                 return rc;
644
645         seq_printf(p, "%d: %s %sACTIVE\n", idx,
646                    obd_uuid2str(&ost_desc->ltd_uuid),
647                    active ? "" : "IN");
648         return 0;
649 }
650
651 static const struct seq_operations lod_osts_sops = {
652         .start  = lod_osts_seq_start,
653         .stop   = lod_osts_seq_stop,
654         .next   = lod_osts_seq_next,
655         .show   = lod_osts_seq_show,
656 };
657
658 static int lod_osts_seq_open(struct inode *inode, struct file *file)
659 {
660         struct seq_file *seq;
661         int rc;
662
663         rc = seq_open(file, &lod_osts_sops);
664         if (rc)
665                 return rc;
666
667         seq = file->private_data;
668         seq->private = PDE_DATA(inode);
669         return 0;
670 }
671
672 LPROC_SEQ_FOPS_RO_TYPE(lod, uuid);
673
674 LPROC_SEQ_FOPS_RO_TYPE(lod, dt_blksize);
675 LPROC_SEQ_FOPS_RO_TYPE(lod, dt_kbytestotal);
676 LPROC_SEQ_FOPS_RO_TYPE(lod, dt_kbytesfree);
677 LPROC_SEQ_FOPS_RO_TYPE(lod, dt_kbytesavail);
678 LPROC_SEQ_FOPS_RO_TYPE(lod, dt_filestotal);
679 LPROC_SEQ_FOPS_RO_TYPE(lod, dt_filesfree);
680
681 /**
682  * Show whether special failout mode for testing is enabled or not.
683  *
684  * \param[in] m         seq file
685  * \param[in] v         unused for single entry
686  *
687  * \retval 0            on success
688  * \retval negative     error code if failed
689  */
690 static int lod_lmv_failout_seq_show(struct seq_file *m, void *v)
691 {
692         struct obd_device *dev = m->private;
693         struct lod_device *lod;
694
695         LASSERT(dev != NULL);
696         lod = lu2lod_dev(dev->obd_lu_dev);
697
698         seq_printf(m, "%d\n", lod->lod_lmv_failout ? 1 : 0);
699         return 0;
700 }
701
702 /**
703  * Enable/disable a special failout mode for testing.
704  *
705  * This determines whether the LMV will try to continue processing a striped
706  * directory even if it has a (partly) corrupted entry in the master directory,
707  * or if it will abort upon finding a corrupted slave directory entry.
708  *
709  * \param[in] file      proc file
710  * \param[in] buffer    string: 0 or non-zero to disable or enable LMV failout
711  * \param[in] count     @buffer length
712  * \param[in] off       unused for single entry
713  *
714  * \retval @count       on success
715  * \retval negative     error code if failed
716  */
717 static ssize_t
718 lod_lmv_failout_seq_write(struct file *file, const char __user *buffer,
719                           size_t count, loff_t *off)
720 {
721         struct seq_file *m = file->private_data;
722         struct obd_device *dev = m->private;
723         struct lod_device *lod;
724         __s64 val = 0;
725         int rc;
726
727         LASSERT(dev != NULL);
728         lod = lu2lod_dev(dev->obd_lu_dev);
729
730         rc = lprocfs_str_to_s64(buffer, count, &val);
731         if (rc)
732                 return rc;
733
734         lod->lod_lmv_failout = !!val;
735
736         return count;
737 }
738 LPROC_SEQ_FOPS(lod_lmv_failout);
739
740 static struct lprocfs_vars lprocfs_lod_obd_vars[] = {
741         { .name =       "uuid",
742           .fops =       &lod_uuid_fops          },
743         { .name =       "stripesize",
744           .fops =       &lod_stripesize_fops    },
745         { .name =       "stripeoffset",
746           .fops =       &lod_stripeoffset_fops  },
747         { .name =       "stripecount",
748           .fops =       &lod_stripecount_fops   },
749         { .name =       "stripetype",
750           .fops =       &lod_stripetype_fops    },
751         { .name =       "numobd",
752           .fops =       &lod_numobd_fops        },
753         { .name =       "activeobd",
754           .fops =       &lod_activeobd_fops     },
755         { .name =       "desc_uuid",
756           .fops =       &lod_desc_uuid_fops     },
757         { .name =       "qos_prio_free",
758           .fops =       &lod_qos_priofree_fops  },
759         { .name =       "qos_threshold_rr",
760           .fops =       &lod_qos_thresholdrr_fops },
761         { .name =       "qos_maxage",
762           .fops =       &lod_qos_maxage_fops    },
763         { .name =       "lmv_failout",
764           .fops =       &lod_lmv_failout_fops   },
765         { NULL }
766 };
767
768 static struct lprocfs_vars lprocfs_lod_osd_vars[] = {
769         { .name = "blocksize",   .fops = &lod_dt_blksize_fops },
770         { .name = "kbytestotal", .fops = &lod_dt_kbytestotal_fops },
771         { .name = "kbytesfree",  .fops = &lod_dt_kbytesfree_fops },
772         { .name = "kbytesavail", .fops = &lod_dt_kbytesavail_fops },
773         { .name = "filestotal",  .fops = &lod_dt_filestotal_fops },
774         { .name = "filesfree",   .fops = &lod_dt_filesfree_fops },
775         { .name = NULL }
776 };
777
778 static const struct file_operations lod_proc_target_fops = {
779         .owner   = THIS_MODULE,
780         .open    = lod_osts_seq_open,
781         .read    = seq_read,
782         .llseek  = seq_lseek,
783         .release = lprocfs_seq_release,
784 };
785
786 /**
787  * Initialize procfs entries for LOD.
788  *
789  * \param[in] lod       LOD device
790  *
791  * \retval 0            on success
792  * \retval negative     error code if failed
793  */
794 int lod_procfs_init(struct lod_device *lod)
795 {
796         struct obd_device       *obd = lod2obd(lod);
797         struct proc_dir_entry   *lov_proc_dir = NULL;
798         struct obd_type         *type;
799         int                      rc;
800
801         obd->obd_vars = lprocfs_lod_obd_vars;
802         rc = lprocfs_obd_setup(obd);
803         if (rc) {
804                 CERROR("%s: cannot setup procfs entry: %d\n",
805                        obd->obd_name, rc);
806                 RETURN(rc);
807         }
808
809         rc = lprocfs_add_vars(obd->obd_proc_entry, lprocfs_lod_osd_vars,
810                               &lod->lod_dt_dev);
811         if (rc) {
812                 CERROR("%s: cannot setup procfs entry: %d\n",
813                        obd->obd_name, rc);
814                 GOTO(out, rc);
815         }
816
817         rc = lprocfs_seq_create(obd->obd_proc_entry, "target_obd",
818                                 0444, &lod_proc_target_fops, obd);
819         if (rc) {
820                 CWARN("%s: Error adding the target_obd file %d\n",
821                       obd->obd_name, rc);
822                 GOTO(out, rc);
823         }
824
825         lod->lod_pool_proc_entry = lprocfs_register("pools",
826                                                     obd->obd_proc_entry,
827                                                     NULL, NULL);
828         if (IS_ERR(lod->lod_pool_proc_entry)) {
829                 rc = PTR_ERR(lod->lod_pool_proc_entry);
830                 lod->lod_pool_proc_entry = NULL;
831                 CWARN("%s: Failed to create pool proc file: %d\n",
832                       obd->obd_name, rc);
833                 GOTO(out, rc);
834         }
835
836         /* If the real LOV is present which is the case for setups
837          * with both server and clients on the same node then use
838          * the LOV's proc root */
839         type = class_search_type(LUSTRE_LOV_NAME);
840         if (type != NULL && type->typ_procroot != NULL)
841                 lov_proc_dir = type->typ_procroot;
842         else
843                 lov_proc_dir = obd->obd_type->typ_procsym;
844
845         if (lov_proc_dir == NULL)
846                 RETURN(0);
847
848         /* for compatibility we link old procfs's LOV entries to lod ones */
849         lod->lod_symlink = lprocfs_add_symlink(obd->obd_name, lov_proc_dir,
850                                                "../lod/%s", obd->obd_name);
851         if (lod->lod_symlink == NULL)
852                 CERROR("cannot create LOV symlink for /proc/fs/lustre/lod/%s\n",
853                        obd->obd_name);
854         RETURN(0);
855
856 out:
857         lprocfs_obd_cleanup(obd);
858
859         return rc;
860 }
861
862 /**
863  * Cleanup procfs entries registred for LOD.
864  *
865  * \param[in] lod       LOD device
866  */
867 void lod_procfs_fini(struct lod_device *lod)
868 {
869         struct obd_device *obd = lod2obd(lod);
870
871         if (lod->lod_symlink != NULL) {
872                 lprocfs_remove(&lod->lod_symlink);
873                 lod->lod_symlink = NULL;
874         }
875
876         if (lod->lod_pool_proc_entry != NULL) {
877                 lprocfs_remove(&lod->lod_pool_proc_entry);
878                 lod->lod_pool_proc_entry = NULL;
879         }
880
881         lprocfs_obd_cleanup(obd);
882 }
883
884 #endif /* CONFIG_PROC_FS */
885