Whamcloud - gitweb
LU-5275 libcfs: merge params_tree.h into lprocfs_status.h
[fs/lustre-release.git] / lustre / obdclass / lprocfs_status.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.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2014, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/obdclass/lprocfs_status.c
37  *
38  * Author: Hariharan Thantry <thantry@users.sourceforge.net>
39  */
40
41 #define DEBUG_SUBSYSTEM S_CLASS
42
43
44 #include <obd_class.h>
45 #include <lprocfs_status.h>
46 #include <lustre/lustre_idl.h>
47
48 #ifdef CONFIG_PROC_FS
49
50 static int lprocfs_no_percpu_stats = 0;
51 CFS_MODULE_PARM(lprocfs_no_percpu_stats, "i", int, 0644,
52                 "Do not alloc percpu data for lprocfs stats");
53
54 #define MAX_STRING_SIZE 128
55
56 int lprocfs_single_release(struct inode *inode, struct file *file)
57 {
58         return single_release(inode, file);
59 }
60 EXPORT_SYMBOL(lprocfs_single_release);
61
62 int lprocfs_seq_release(struct inode *inode, struct file *file)
63 {
64         return seq_release(inode, file);
65 }
66 EXPORT_SYMBOL(lprocfs_seq_release);
67
68 struct proc_dir_entry *
69 lprocfs_add_simple(struct proc_dir_entry *root, char *name,
70                    void *data, const struct file_operations *fops)
71 {
72         struct proc_dir_entry *proc;
73         mode_t mode = 0;
74
75         if (root == NULL || name == NULL || fops == NULL)
76                 return ERR_PTR(-EINVAL);
77
78         if (fops->read)
79                 mode = 0444;
80         if (fops->write)
81                 mode |= 0200;
82         proc = proc_create_data(name, mode, root, fops, data);
83         if (!proc) {
84                 CERROR("LprocFS: No memory to create /proc entry %s\n",
85                        name);
86                 return ERR_PTR(-ENOMEM);
87         }
88         return proc;
89 }
90 EXPORT_SYMBOL(lprocfs_add_simple);
91
92 struct proc_dir_entry *lprocfs_add_symlink(const char *name,
93                         struct proc_dir_entry *parent, const char *format, ...)
94 {
95         struct proc_dir_entry *entry;
96         char *dest;
97         va_list ap;
98
99         if (parent == NULL || format == NULL)
100                 return NULL;
101
102         OBD_ALLOC_WAIT(dest, MAX_STRING_SIZE + 1);
103         if (dest == NULL)
104                 return NULL;
105
106         va_start(ap, format);
107         vsnprintf(dest, MAX_STRING_SIZE, format, ap);
108         va_end(ap);
109
110         entry = proc_symlink(name, parent, dest);
111         if (entry == NULL)
112                 CERROR("LprocFS: Could not create symbolic link from "
113                        "%s to %s\n", name, dest);
114
115         OBD_FREE(dest, MAX_STRING_SIZE + 1);
116         return entry;
117 }
118 EXPORT_SYMBOL(lprocfs_add_symlink);
119
120 #ifdef HAVE_ONLY_PROCFS_SEQ
121 static const struct file_operations lprocfs_generic_fops = { };
122 #else
123
124 ssize_t
125 lprocfs_fops_read(struct file *f, char __user *buf, size_t size, loff_t *ppos)
126 {
127         struct inode *inode = f->f_dentry->d_inode;
128         struct proc_dir_entry *dp = PDE(inode);
129         char *page, *start = NULL;
130         int rc, eof = 1, count;
131
132         if (*ppos >= PAGE_CACHE_SIZE)
133                 return 0;
134
135         page = (char *)__get_free_page(GFP_KERNEL);
136         if (page == NULL)
137                 return -ENOMEM;
138
139         rc = LPROCFS_ENTRY_CHECK(inode);
140         if (rc < 0)
141                 goto out;
142
143         OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
144         if (dp->read_proc != NULL)
145                 rc = dp->read_proc(page, &start, *ppos, PAGE_CACHE_SIZE,
146                                    &eof, dp->data);
147         else
148                 rc = 0;
149
150         if (rc <= 0)
151                 goto out;
152
153         /* for lustre proc read, the read count must be less than PAGE_SIZE */
154         LASSERT(eof == 1);
155
156         if (start == NULL) {
157                 rc -= *ppos;
158                 if (rc < 0)
159                         rc = 0;
160                 if (rc == 0)
161                         goto out;
162                 start = page + *ppos;
163         } else if (start < page) {
164                 start = page;
165         }
166
167         count = (rc < size) ? rc : size;
168         if (copy_to_user(buf, start, count)) {
169                 rc = -EFAULT;
170                 goto out;
171         }
172         *ppos += count;
173
174 out:
175         free_page((unsigned long)page);
176         return rc;
177 }
178
179 ssize_t
180 lprocfs_fops_write(struct file *f, const char __user *buf, size_t size,
181                    loff_t *ppos)
182 {
183         struct inode *inode = f->f_dentry->d_inode;
184         struct proc_dir_entry *dp = PDE(inode);
185         int rc;
186
187         rc = LPROCFS_ENTRY_CHECK(inode);
188         if (rc < 0)
189                 return rc;
190
191         if (dp->write_proc != NULL)
192                 rc = dp->write_proc(f, buf, size, dp->data);
193         else
194                 rc = -EIO;
195
196         return rc;
197 }
198
199 static struct file_operations lprocfs_generic_fops = {
200         .owner = THIS_MODULE,
201         .read = lprocfs_fops_read,
202         .write = lprocfs_fops_write,
203 };
204
205 /* for b=10866, global variable */
206 DECLARE_RWSEM(_lprocfs_lock);
207 EXPORT_SYMBOL(_lprocfs_lock);
208
209 static struct proc_dir_entry *__lprocfs_srch(struct proc_dir_entry *head,
210                                              const char *name)
211 {
212         struct proc_dir_entry *temp;
213
214         if (head == NULL)
215                 return NULL;
216
217         temp = head->subdir;
218         while (temp != NULL) {
219                 if (strcmp(temp->name, name) == 0)
220                         return temp;
221                 temp = temp->next;
222         }
223         return NULL;
224 }
225
226 struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
227                                     const char *name)
228 {
229         struct proc_dir_entry *temp;
230
231         down_read(&_lprocfs_lock);
232         temp = __lprocfs_srch(head, name);
233         up_read(&_lprocfs_lock);
234         return temp;
235 }
236 EXPORT_SYMBOL(lprocfs_srch);
237
238 static int __lprocfs_add_vars(struct proc_dir_entry *root,
239                               struct lprocfs_vars *list,
240                               void *data)
241 {
242         int rc = 0;
243
244         if (root == NULL || list == NULL)
245                 return -EINVAL;
246
247         while (list->name != NULL) {
248                 struct proc_dir_entry *cur_root, *proc;
249                 char *pathcopy, *cur, *next, pathbuf[64];
250                 int pathsize = strlen(list->name) + 1;
251
252                 proc = NULL;
253                 cur_root = root;
254
255                 /* need copy of path for strsep */
256                 if (strlen(list->name) > sizeof(pathbuf) - 1) {
257                         OBD_ALLOC(pathcopy, pathsize);
258                         if (pathcopy == NULL)
259                                 GOTO(out, rc = -ENOMEM);
260                 } else {
261                         pathcopy = pathbuf;
262                 }
263
264                 next = pathcopy;
265                 strcpy(pathcopy, list->name);
266
267                 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
268                         if (*cur =='\0') /* skip double/trailing "/" */
269                                 continue;
270
271                         proc = __lprocfs_srch(cur_root, cur);
272                         CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
273                                cur_root->name, cur, next,
274                                (proc ? "exists" : "new"));
275                         if (next != NULL) {
276                                 cur_root = (proc ? proc :
277                                             proc_mkdir(cur, cur_root));
278                         } else if (proc == NULL) {
279                                 mode_t mode = 0;
280                                 if (list->proc_mode != 0000) {
281                                         mode = list->proc_mode;
282                                 } else {
283                                         if (list->read_fptr)
284                                                 mode = 0444;
285                                         if (list->write_fptr)
286                                                 mode |= 0200;
287                                 }
288                                 proc = create_proc_entry(cur, mode, cur_root);
289                         }
290                 }
291
292                 if (pathcopy != pathbuf)
293                         OBD_FREE(pathcopy, pathsize);
294
295                 if (cur_root == NULL || proc == NULL) {
296                         CERROR("LprocFS: No memory to create /proc entry %s\n",
297                                list->name);
298                         GOTO(out, rc = -ENOMEM);
299                 }
300
301                 if (list->fops)
302                         proc->proc_fops = list->fops;
303                 else
304                         proc->proc_fops = &lprocfs_generic_fops;
305                 proc->read_proc = list->read_fptr;
306                 proc->write_proc = list->write_fptr;
307                 proc->data = (list->data ? list->data : data);
308                 list++;
309         }
310 out:
311         return rc;
312 }
313
314 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
315                      void *data)
316 {
317         int rc = 0;
318
319         down_write(&_lprocfs_lock);
320         rc = __lprocfs_add_vars(root, list, data);
321         up_write(&_lprocfs_lock);
322
323         return rc;
324 }
325 EXPORT_SYMBOL(lprocfs_add_vars);
326 #endif
327
328 /**
329  * Add /proc entries.
330  *
331  * \param root [in]  The parent proc entry on which new entry will be added.
332  * \param list [in]  Array of proc entries to be added.
333  * \param data [in]  The argument to be passed when entries read/write routines
334  *                   are called through /proc file.
335  *
336  * \retval 0   on success
337  *         < 0 on error
338  */
339 int
340 lprocfs_seq_add_vars(struct proc_dir_entry *root, struct lprocfs_seq_vars *list,
341                      void *data)
342 {
343         if (root == NULL || list == NULL)
344                 return -EINVAL;
345
346         while (list->name != NULL) {
347                 struct proc_dir_entry *proc;
348                 mode_t mode = 0;
349
350                 if (list->proc_mode != 0000) {
351                         mode = list->proc_mode;
352                 } else if (list->fops) {
353                         if (list->fops->read)
354                                 mode = 0444;
355                         if (list->fops->write)
356                                 mode |= 0200;
357                 }
358                 proc = proc_create_data(list->name, mode, root,
359                                         list->fops ?: &lprocfs_generic_fops,
360                                         list->data ?: data);
361                 if (proc == NULL)
362                         return -ENOMEM;
363                 list++;
364         }
365         return 0;
366 }
367 EXPORT_SYMBOL(lprocfs_seq_add_vars);
368
369 #ifndef HAVE_ONLY_PROCFS_SEQ
370 static void lprocfs_remove_nolock(struct proc_dir_entry **proot)
371 {
372         struct proc_dir_entry *root = *proot;
373         struct proc_dir_entry *temp = root;
374         struct proc_dir_entry *rm_entry;
375         struct proc_dir_entry *parent;
376
377         *proot = NULL;
378         if (root == NULL || IS_ERR(root))
379                 return;
380
381         parent = root->parent;
382         LASSERT(parent != NULL);
383
384         while (1) {
385                 while (temp->subdir != NULL)
386                         temp = temp->subdir;
387
388                 rm_entry = temp;
389                 temp = temp->parent;
390
391                 /* Memory corruption once caused this to fail, and
392                    without this LASSERT we would loop here forever. */
393                 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
394                          "0x%p  %s/%s len %d\n", rm_entry, temp->name,
395                          rm_entry->name, (int)strlen(rm_entry->name));
396
397                 remove_proc_entry(rm_entry->name, temp);
398                 if (temp == parent)
399                         break;
400         }
401 }
402 #endif
403
404 void lprocfs_remove(struct proc_dir_entry **rooth)
405 {
406 #ifndef HAVE_ONLY_PROCFS_SEQ
407         down_write(&_lprocfs_lock); /* search vs remove race */
408         lprocfs_remove_nolock(rooth);
409         up_write(&_lprocfs_lock);
410 #else
411         proc_remove(*rooth);
412         *rooth = NULL;
413 #endif
414 }
415 EXPORT_SYMBOL(lprocfs_remove);
416
417 void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
418 {
419         LASSERT(parent != NULL);
420         remove_proc_entry(name, parent);
421 }
422 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
423
424 #ifndef HAVE_ONLY_PROCFS_SEQ
425 void lprocfs_try_remove_proc_entry(const char *name,
426                                    struct proc_dir_entry *parent)
427 {
428         struct proc_dir_entry    *t = NULL;
429         struct proc_dir_entry   **p;
430         int                       len, busy = 0;
431
432         LASSERT(parent != NULL);
433         len = strlen(name);
434
435         down_write(&_lprocfs_lock);
436         /* lookup target name */
437         for (p = &parent->subdir; *p; p = &(*p)->next) {
438                 if ((*p)->namelen != len)
439                         continue;
440                 if (memcmp(name, (*p)->name, len))
441                         continue;
442                 t = *p;
443                 break;
444         }
445
446         if (t) {
447                 /* verify it's empty: do not count "num_refs" */
448                 for (p = &t->subdir; *p; p = &(*p)->next) {
449                         if ((*p)->namelen != strlen("num_refs")) {
450                                 busy = 1;
451                                 break;
452                         }
453                         if (memcmp("num_refs", (*p)->name,
454                                    strlen("num_refs"))) {
455                                 busy = 1;
456                                 break;
457                         }
458                 }
459         }
460
461         if (busy == 0)
462                 lprocfs_remove_nolock(&t);
463
464         up_write(&_lprocfs_lock);
465         return;
466 }
467 EXPORT_SYMBOL(lprocfs_try_remove_proc_entry);
468
469 struct proc_dir_entry *lprocfs_register(const char *name,
470                                         struct proc_dir_entry *parent,
471                                         struct lprocfs_vars *list, void *data)
472 {
473         struct proc_dir_entry *entry;
474         int rc;
475
476         down_write(&_lprocfs_lock);
477         entry = __lprocfs_srch(parent, name);
478         if (entry != NULL) {
479                 CERROR("entry '%s' already registered\n", name);
480                 GOTO(out, entry = ERR_PTR(-EALREADY));
481         }
482
483         entry = proc_mkdir(name, parent);
484         if (entry == NULL)
485                 GOTO(out, entry = ERR_PTR(-ENOMEM));
486
487         if (list != NULL) {
488                 rc = __lprocfs_add_vars(entry, list, data);
489                 if (rc != 0) {
490                         lprocfs_remove_nolock(&entry);
491                         GOTO(out, entry = ERR_PTR(rc));
492                 }
493         }
494 out:
495         up_write(&_lprocfs_lock);
496         return entry;
497 }
498 EXPORT_SYMBOL(lprocfs_register);
499 #endif
500
501 struct proc_dir_entry *
502 lprocfs_seq_register(const char *name, struct proc_dir_entry *parent,
503                      struct lprocfs_seq_vars *list, void *data)
504 {
505         struct proc_dir_entry *newchild;
506
507         newchild = proc_mkdir(name, parent);
508         if (newchild == NULL)
509                 return ERR_PTR(-ENOMEM);
510
511         if (list != NULL) {
512                 int rc = lprocfs_seq_add_vars(newchild, list, data);
513                 if (rc) {
514                         lprocfs_remove(&newchild);
515                         return ERR_PTR(rc);
516                 }
517         }
518         return newchild;
519 }
520 EXPORT_SYMBOL(lprocfs_seq_register);
521
522 /* Generic callbacks */
523 int lprocfs_uint_seq_show(struct seq_file *m, void *data)
524 {
525         return seq_printf(m, "%u\n", *(unsigned int *)data);
526 }
527 EXPORT_SYMBOL(lprocfs_uint_seq_show);
528
529 int lprocfs_wr_uint(struct file *file, const char __user *buffer,
530                     unsigned long count, void *data)
531 {
532         unsigned *p = data;
533         char dummy[MAX_STRING_SIZE + 1], *end;
534         unsigned long tmp;
535
536         dummy[MAX_STRING_SIZE] = '\0';
537         if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))
538                 return -EFAULT;
539
540         tmp = simple_strtoul(dummy, &end, 0);
541         if (dummy == end)
542                 return -EINVAL;
543
544         *p = (unsigned int)tmp;
545         return count;
546 }
547 EXPORT_SYMBOL(lprocfs_wr_uint);
548
549 ssize_t lprocfs_uint_seq_write(struct file *file, const char __user *buffer,
550                                size_t count, loff_t *off)
551 {
552         int *data = ((struct seq_file *)file->private_data)->private;
553         int val = 0, rc;
554
555         rc = lprocfs_write_helper(buffer, count, &val);
556         if (rc < 0)
557                 return rc;
558
559         return lprocfs_wr_uint(file, buffer, count, data);
560 }
561 EXPORT_SYMBOL(lprocfs_uint_seq_write);
562
563 int lprocfs_u64_seq_show(struct seq_file *m, void *data)
564 {
565         LASSERT(data != NULL);
566         return seq_printf(m, LPU64"\n", *(__u64 *)data);
567 }
568 EXPORT_SYMBOL(lprocfs_u64_seq_show);
569
570 int lprocfs_atomic_seq_show(struct seq_file *m, void *data)
571 {
572         atomic_t *atom = data;
573         LASSERT(atom != NULL);
574         return seq_printf(m, "%d\n", atomic_read(atom));
575 }
576 EXPORT_SYMBOL(lprocfs_atomic_seq_show);
577
578 ssize_t
579 lprocfs_atomic_seq_write(struct file *file, const char __user *buffer,
580                         size_t count, loff_t *off)
581 {
582         atomic_t *atm = ((struct seq_file *)file->private_data)->private;
583         int val = 0;
584         int rc;
585
586         rc = lprocfs_write_helper(buffer, count, &val);
587         if (rc < 0)
588                 return rc;
589
590         if (val <= 0)
591                 return -ERANGE;
592
593         atomic_set(atm, val);
594         return count;
595 }
596 EXPORT_SYMBOL(lprocfs_atomic_seq_write);
597
598 int lprocfs_uuid_seq_show(struct seq_file *m, void *data)
599 {
600         struct obd_device *obd = data;
601
602         LASSERT(obd != NULL);
603         return seq_printf(m, "%s\n", obd->obd_uuid.uuid);
604 }
605 EXPORT_SYMBOL(lprocfs_uuid_seq_show);
606
607 int lprocfs_name_seq_show(struct seq_file *m, void *data)
608 {
609         struct obd_device *dev = data;
610
611         LASSERT(dev != NULL);
612         return seq_printf(m, "%s\n", dev->obd_name);
613 }
614 EXPORT_SYMBOL(lprocfs_name_seq_show);
615
616 int lprocfs_blksize_seq_show(struct seq_file *m, void *data)
617 {
618         struct obd_device *obd = data;
619         struct obd_statfs  osfs;
620         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
621                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
622                             OBD_STATFS_NODELAY);
623         if (!rc)
624                 rc = seq_printf(m, "%u\n", osfs.os_bsize);
625         return rc;
626 }
627 EXPORT_SYMBOL(lprocfs_blksize_seq_show);
628
629 int lprocfs_kbytestotal_seq_show(struct seq_file *m, void *data)
630 {
631         struct obd_device *obd = data;
632         struct obd_statfs  osfs;
633         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
634                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
635                             OBD_STATFS_NODELAY);
636         if (!rc) {
637                 __u32 blk_size = osfs.os_bsize >> 10;
638                 __u64 result = osfs.os_blocks;
639
640                 while (blk_size >>= 1)
641                         result <<= 1;
642
643                 rc = seq_printf(m, LPU64"\n", result);
644         }
645         return rc;
646 }
647 EXPORT_SYMBOL(lprocfs_kbytestotal_seq_show);
648
649 int lprocfs_kbytesfree_seq_show(struct seq_file *m, void *data)
650 {
651         struct obd_device *obd = data;
652         struct obd_statfs  osfs;
653         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
654                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
655                             OBD_STATFS_NODELAY);
656         if (!rc) {
657                 __u32 blk_size = osfs.os_bsize >> 10;
658                 __u64 result = osfs.os_bfree;
659
660                 while (blk_size >>= 1)
661                         result <<= 1;
662
663                 rc = seq_printf(m, LPU64"\n", result);
664         }
665         return rc;
666 }
667 EXPORT_SYMBOL(lprocfs_kbytesfree_seq_show);
668
669 int lprocfs_kbytesavail_seq_show(struct seq_file *m, void *data)
670 {
671         struct obd_device *obd = data;
672         struct obd_statfs  osfs;
673         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
674                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
675                             OBD_STATFS_NODELAY);
676         if (!rc) {
677                 __u32 blk_size = osfs.os_bsize >> 10;
678                 __u64 result = osfs.os_bavail;
679
680                 while (blk_size >>= 1)
681                         result <<= 1;
682
683                 rc = seq_printf(m, LPU64"\n", result);
684         }
685         return rc;
686 }
687 EXPORT_SYMBOL(lprocfs_kbytesavail_seq_show);
688
689 int lprocfs_filestotal_seq_show(struct seq_file *m, void *data)
690 {
691         struct obd_device *obd = data;
692         struct obd_statfs  osfs;
693         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
694                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
695                             OBD_STATFS_NODELAY);
696         if (!rc)
697                 rc = seq_printf(m, LPU64"\n", osfs.os_files);
698         return rc;
699 }
700 EXPORT_SYMBOL(lprocfs_filestotal_seq_show);
701
702 int lprocfs_filesfree_seq_show(struct seq_file *m, void *data)
703 {
704         struct obd_device *obd = data;
705         struct obd_statfs  osfs;
706         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
707                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
708                             OBD_STATFS_NODELAY);
709         if (!rc)
710                 rc = seq_printf(m, LPU64"\n", osfs.os_ffree);
711         return rc;
712 }
713 EXPORT_SYMBOL(lprocfs_filesfree_seq_show);
714
715 int lprocfs_server_uuid_seq_show(struct seq_file *m, void *data)
716 {
717         struct obd_device *obd = data;
718         struct obd_import *imp;
719         char *imp_state_name = NULL;
720         int rc = 0;
721
722         LASSERT(obd != NULL);
723         LPROCFS_CLIMP_CHECK(obd);
724         imp = obd->u.cli.cl_import;
725         imp_state_name = ptlrpc_import_state_name(imp->imp_state);
726         rc = seq_printf(m, "%s\t%s%s\n", obd2cli_tgt(obd), imp_state_name,
727                         imp->imp_deactive ? "\tDEACTIVATED" : "");
728
729         LPROCFS_CLIMP_EXIT(obd);
730         return rc;
731 }
732 EXPORT_SYMBOL(lprocfs_server_uuid_seq_show);
733
734 int lprocfs_conn_uuid_seq_show(struct seq_file *m, void *data)
735 {
736         struct obd_device *obd = data;
737         struct ptlrpc_connection *conn;
738         int rc = 0;
739
740         LASSERT(obd != NULL);
741
742         LPROCFS_CLIMP_CHECK(obd);
743         conn = obd->u.cli.cl_import->imp_connection;
744         if (conn && obd->u.cli.cl_import)
745                 rc = seq_printf(m, "%s\n", conn->c_remote_uuid.uuid);
746         else
747                 rc = seq_printf(m, "%s\n", "<none>");
748
749         LPROCFS_CLIMP_EXIT(obd);
750         return rc;
751 }
752 EXPORT_SYMBOL(lprocfs_conn_uuid_seq_show);
753
754 /** add up per-cpu counters */
755 void lprocfs_stats_collect(struct lprocfs_stats *stats, int idx,
756                            struct lprocfs_counter *cnt)
757 {
758         unsigned int                    num_entry;
759         struct lprocfs_counter          *percpu_cntr;
760         int                             i;
761         unsigned long                   flags = 0;
762
763         memset(cnt, 0, sizeof(*cnt));
764
765         if (stats == NULL) {
766                 /* set count to 1 to avoid divide-by-zero errs in callers */
767                 cnt->lc_count = 1;
768                 return;
769         }
770
771         cnt->lc_min = LC_MIN_INIT;
772
773         num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
774
775         for (i = 0; i < num_entry; i++) {
776                 if (stats->ls_percpu[i] == NULL)
777                         continue;
778                 percpu_cntr = lprocfs_stats_counter_get(stats, i, idx);
779
780                 cnt->lc_count += percpu_cntr->lc_count;
781                 cnt->lc_sum += percpu_cntr->lc_sum;
782                 if (percpu_cntr->lc_min < cnt->lc_min)
783                         cnt->lc_min = percpu_cntr->lc_min;
784                 if (percpu_cntr->lc_max > cnt->lc_max)
785                         cnt->lc_max = percpu_cntr->lc_max;
786                 cnt->lc_sumsquare += percpu_cntr->lc_sumsquare;
787         }
788
789         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
790 }
791 EXPORT_SYMBOL(lprocfs_stats_collect);
792
793 /**
794  * Append a space separated list of current set flags to str.
795  */
796 #define flag2str(flag)                                          \
797         do {                                                            \
798                 if (imp->imp_##flag) {                                  \
799                         seq_printf(m, "%s" #flag, first ? "" : ", ");   \
800                         first = false;                                  \
801                 }                                                       \
802         } while (0)
803 static void obd_import_flags2str(struct obd_import *imp, struct seq_file *m)
804 {
805         bool first = true;
806
807         if (imp->imp_obd->obd_no_recov) {
808                 seq_printf(m, "no_recov");
809                 first = false;
810         }
811
812         flag2str(invalid);
813         flag2str(deactive);
814         flag2str(replayable);
815         flag2str(delayed_recovery);
816         flag2str(no_lock_replay);
817         flag2str(vbr_failed);
818         flag2str(pingable);
819         flag2str(resend_replay);
820         flag2str(no_pinger_recover);
821         flag2str(need_mne_swab);
822         flag2str(connect_tried);
823 }
824 #undef flag2str
825
826 static const char *obd_connect_names[] = {
827         "read_only",
828         "lov_index",
829         "connect_from_mds",
830         "write_grant",
831         "server_lock",
832         "version",
833         "request_portal",
834         "acl",
835         "xattr",
836         "create_on_write",
837         "truncate_lock",
838         "initial_transno",
839         "inode_bit_locks",
840         "join_file(obsolete)",
841         "getattr_by_fid",
842         "no_oh_for_devices",
843         "remote_client",
844         "remote_client_by_force",
845         "max_byte_per_rpc",
846         "64bit_qdata",
847         "mds_capability",
848         "oss_capability",
849         "early_lock_cancel",
850         "som",
851         "adaptive_timeouts",
852         "lru_resize",
853         "mds_mds_connection",
854         "real_conn",
855         "change_qunit_size",
856         "alt_checksum_algorithm",
857         "fid_is_enabled",
858         "version_recovery",
859         "pools",
860         "grant_shrink",
861         "skip_orphan",
862         "large_ea",
863         "full20",
864         "layout_lock",
865         "64bithash",
866         "object_max_bytes",
867         "imp_recov",
868         "jobstats",
869         "umask",
870         "einprogress",
871         "grant_param",
872         "flock_owner",
873         "lvb_type",
874         "nanoseconds_times",
875         "lightweight_conn",
876         "short_io",
877         "pingless",
878         "flock_deadlock",
879         "disp_stripe",
880         "open_by_fid",
881         "lfsck",
882         "unknown",
883         "unlink_close",
884         "unknown",
885         "dir_stripe",
886         "unknown",
887         NULL
888 };
889
890 static void obd_connect_seq_flags2str(struct seq_file *m, __u64 flags, char *sep)
891 {
892         bool first = true;
893         __u64 mask = 1;
894         int i;
895
896         for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
897                 if (flags & mask) {
898                         seq_printf(m, "%s%s",
899                                    first ? "" : sep, obd_connect_names[i]);
900                         first = false;
901                 }
902         }
903         if (flags & ~(mask - 1))
904                 seq_printf(m, "%sunknown_"LPX64,
905                            first ? "" : sep, flags & ~(mask - 1));
906 }
907
908 int obd_connect_flags2str(char *page, int count, __u64 flags, char *sep)
909 {
910         __u64 mask = 1;
911         int i, ret = 0;
912
913         for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
914                 if (flags & mask)
915                         ret += snprintf(page + ret, count - ret, "%s%s",
916                                         ret ? sep : "", obd_connect_names[i]);
917         }
918         if (flags & ~(mask - 1))
919                 ret += snprintf(page + ret, count - ret,
920                                 "%sunknown_"LPX64,
921                                 ret ? sep : "", flags & ~(mask - 1));
922         return ret;
923 }
924 EXPORT_SYMBOL(obd_connect_flags2str);
925
926 static void obd_connect_data_seqprint(struct seq_file *m,
927                                       struct obd_connect_data *ocd)
928 {
929         int flags;
930
931         LASSERT(ocd != NULL);
932         flags = ocd->ocd_connect_flags;
933
934         seq_printf(m, "    connect_data:\n"
935                       "       flags: "LPX64"\n"
936                       "       instance: %u\n",
937                       ocd->ocd_connect_flags,
938                       ocd->ocd_instance);
939         if (flags & OBD_CONNECT_VERSION)
940                 seq_printf(m, "       target_version: %u.%u.%u.%u\n",
941                               OBD_OCD_VERSION_MAJOR(ocd->ocd_version),
942                               OBD_OCD_VERSION_MINOR(ocd->ocd_version),
943                               OBD_OCD_VERSION_PATCH(ocd->ocd_version),
944                               OBD_OCD_VERSION_FIX(ocd->ocd_version));
945         if (flags & OBD_CONNECT_MDS)
946                 seq_printf(m, "       mdt_index: %d\n", ocd->ocd_group);
947         if (flags & OBD_CONNECT_GRANT)
948                 seq_printf(m, "       initial_grant: %d\n", ocd->ocd_grant);
949         if (flags & OBD_CONNECT_INDEX)
950                 seq_printf(m, "       target_index: %u\n", ocd->ocd_index);
951         if (flags & OBD_CONNECT_BRW_SIZE)
952                 seq_printf(m, "       max_brw_size: %d\n", ocd->ocd_brw_size);
953         if (flags & OBD_CONNECT_IBITS)
954                 seq_printf(m, "       ibits_known: "LPX64"\n",
955                                 ocd->ocd_ibits_known);
956         if (flags & OBD_CONNECT_GRANT_PARAM)
957                 seq_printf(m, "       grant_block_size: %d\n"
958                               "       grant_inode_size: %d\n"
959                               "       grant_extent_overhead: %d\n",
960                               ocd->ocd_blocksize,
961                               ocd->ocd_inodespace,
962                               ocd->ocd_grant_extent);
963         if (flags & OBD_CONNECT_TRANSNO)
964                 seq_printf(m, "       first_transno: "LPX64"\n",
965                                 ocd->ocd_transno);
966         if (flags & OBD_CONNECT_CKSUM)
967                 seq_printf(m, "       cksum_types: %#x\n",
968                               ocd->ocd_cksum_types);
969         if (flags & OBD_CONNECT_MAX_EASIZE)
970                 seq_printf(m, "       max_easize: %d\n", ocd->ocd_max_easize);
971         if (flags & OBD_CONNECT_MAXBYTES)
972                 seq_printf(m, "       max_object_bytes: "LPU64"\n",
973                               ocd->ocd_maxbytes);
974 }
975
976 int lprocfs_import_seq_show(struct seq_file *m, void *data)
977 {
978         struct lprocfs_counter          ret;
979         struct lprocfs_counter_header   *header;
980         struct obd_device               *obd    = (struct obd_device *)data;
981         struct obd_import               *imp;
982         struct obd_import_conn          *conn;
983         struct obd_connect_data         *ocd;
984         int                             j;
985         int                             k;
986         int                             rw      = 0;
987
988         LASSERT(obd != NULL);
989         LPROCFS_CLIMP_CHECK(obd);
990         imp = obd->u.cli.cl_import;
991         ocd = &imp->imp_connect_data;
992
993         seq_printf(m, "import:\n"
994                       "    name: %s\n"
995                       "    target: %s\n"
996                       "    state: %s\n"
997                       "    connect_flags: [ ",
998                       obd->obd_name,
999                       obd2cli_tgt(obd),
1000                       ptlrpc_import_state_name(imp->imp_state));
1001         obd_connect_seq_flags2str(m, imp->imp_connect_data.ocd_connect_flags,
1002                                         ", ");
1003         seq_printf(m, " ]\n");
1004         obd_connect_data_seqprint(m, ocd);
1005         seq_printf(m, "    import_flags: [ ");
1006         obd_import_flags2str(imp, m);
1007
1008         seq_printf(m, " ]\n"
1009                       "    connection:\n"
1010                       "       failover_nids: [ ");
1011         spin_lock(&imp->imp_lock);
1012         j = 0;
1013         list_for_each_entry(conn, &imp->imp_conn_list, oic_item) {
1014                 seq_printf(m, "%s%s", j ? ", " : "",
1015                            libcfs_nid2str(conn->oic_conn->c_peer.nid));
1016                 j++;
1017         }
1018         seq_printf(m, " ]\n"
1019                       "       current_connection: %s\n"
1020                       "       connection_attempts: %u\n"
1021                       "       generation: %u\n"
1022                       "       in-progress_invalidations: %u\n",
1023                       imp->imp_connection == NULL ? "<none>" :
1024                               libcfs_nid2str(imp->imp_connection->c_peer.nid),
1025                       imp->imp_conn_cnt,
1026                       imp->imp_generation,
1027                       atomic_read(&imp->imp_inval_count));
1028         spin_unlock(&imp->imp_lock);
1029
1030         if (obd->obd_svc_stats == NULL)
1031                 goto out_climp;
1032
1033         header = &obd->obd_svc_stats->ls_cnt_header[PTLRPC_REQWAIT_CNTR];
1034         lprocfs_stats_collect(obd->obd_svc_stats, PTLRPC_REQWAIT_CNTR, &ret);
1035         if (ret.lc_count != 0) {
1036                 /* first argument to do_div MUST be __u64 */
1037                 __u64 sum = ret.lc_sum;
1038                 do_div(sum, ret.lc_count);
1039                 ret.lc_sum = sum;
1040         } else
1041                 ret.lc_sum = 0;
1042         seq_printf(m, "    rpcs:\n"
1043                       "       inflight: %u\n"
1044                       "       unregistering: %u\n"
1045                       "       timeouts: %u\n"
1046                       "       avg_waittime: "LPU64" %s\n",
1047                       atomic_read(&imp->imp_inflight),
1048                       atomic_read(&imp->imp_unregistering),
1049                       atomic_read(&imp->imp_timeouts),
1050                       ret.lc_sum, header->lc_units);
1051
1052         k = 0;
1053         for(j = 0; j < IMP_AT_MAX_PORTALS; j++) {
1054                 if (imp->imp_at.iat_portal[j] == 0)
1055                         break;
1056                 k = max_t(unsigned int, k,
1057                           at_get(&imp->imp_at.iat_service_estimate[j]));
1058         }
1059         seq_printf(m, "    service_estimates:\n"
1060                       "       services: %u sec\n"
1061                       "       network: %u sec\n",
1062                       k,
1063                       at_get(&imp->imp_at.iat_net_latency));
1064
1065         seq_printf(m, "    transactions:\n"
1066                       "       last_replay: "LPU64"\n"
1067                       "       peer_committed: "LPU64"\n"
1068                       "       last_checked: "LPU64"\n",
1069                       imp->imp_last_replay_transno,
1070                       imp->imp_peer_committed_transno,
1071                       imp->imp_last_transno_checked);
1072
1073         /* avg data rates */
1074         for (rw = 0; rw <= 1; rw++) {
1075                 lprocfs_stats_collect(obd->obd_svc_stats,
1076                                       PTLRPC_LAST_CNTR + BRW_READ_BYTES + rw,
1077                                       &ret);
1078                 if (ret.lc_sum > 0 && ret.lc_count > 0) {
1079                         /* first argument to do_div MUST be __u64 */
1080                         __u64 sum = ret.lc_sum;
1081                         do_div(sum, ret.lc_count);
1082                         ret.lc_sum = sum;
1083                         seq_printf(m, "    %s_data_averages:\n"
1084                                       "       bytes_per_rpc: "LPU64"\n",
1085                                       rw ? "write" : "read",
1086                                       ret.lc_sum);
1087                 }
1088                 k = (int)ret.lc_sum;
1089                 j = opcode_offset(OST_READ + rw) + EXTRA_MAX_OPCODES;
1090                 header = &obd->obd_svc_stats->ls_cnt_header[j];
1091                 lprocfs_stats_collect(obd->obd_svc_stats, j, &ret);
1092                 if (ret.lc_sum > 0 && ret.lc_count != 0) {
1093                         /* first argument to do_div MUST be __u64 */
1094                         __u64 sum = ret.lc_sum;
1095                         do_div(sum, ret.lc_count);
1096                         ret.lc_sum = sum;
1097                         seq_printf(m, "       %s_per_rpc: "LPU64"\n",
1098                                         header->lc_units, ret.lc_sum);
1099                         j = (int)ret.lc_sum;
1100                         if (j > 0)
1101                                 seq_printf(m, "       MB_per_sec: %u.%.02u\n",
1102                                                 k / j, (100 * k / j) % 100);
1103                 }
1104         }
1105
1106 out_climp:
1107         LPROCFS_CLIMP_EXIT(obd);
1108         return 0;
1109 }
1110 EXPORT_SYMBOL(lprocfs_import_seq_show);
1111
1112 int lprocfs_state_seq_show(struct seq_file *m, void *data)
1113 {
1114         struct obd_device *obd = (struct obd_device *)data;
1115         struct obd_import *imp;
1116         int j, k;
1117
1118         LASSERT(obd != NULL);
1119         LPROCFS_CLIMP_CHECK(obd);
1120         imp = obd->u.cli.cl_import;
1121
1122         seq_printf(m, "current_state: %s\n",
1123                    ptlrpc_import_state_name(imp->imp_state));
1124         seq_printf(m, "state_history:\n");
1125         k = imp->imp_state_hist_idx;
1126         for (j = 0; j < IMP_STATE_HIST_LEN; j++) {
1127                 struct import_state_hist *ish =
1128                         &imp->imp_state_hist[(k + j) % IMP_STATE_HIST_LEN];
1129                 if (ish->ish_state == 0)
1130                         continue;
1131                 seq_printf(m, " - [ "CFS_TIME_T", %s ]\n",
1132                            ish->ish_time,
1133                 ptlrpc_import_state_name(ish->ish_state));
1134         }
1135
1136         LPROCFS_CLIMP_EXIT(obd);
1137         return 0;
1138 }
1139 EXPORT_SYMBOL(lprocfs_state_seq_show);
1140
1141 int lprocfs_seq_at_hist_helper(struct seq_file *m, struct adaptive_timeout *at)
1142 {
1143         int i;
1144         for (i = 0; i < AT_BINS; i++)
1145                 seq_printf(m, "%3u ", at->at_hist[i]);
1146         seq_printf(m, "\n");
1147         return 0;
1148 }
1149 EXPORT_SYMBOL(lprocfs_seq_at_hist_helper);
1150
1151 /* See also ptlrpc_lprocfs_timeouts_show_seq */
1152 int lprocfs_timeouts_seq_show(struct seq_file *m, void *data)
1153 {
1154         struct obd_device *obd = (struct obd_device *)data;
1155         struct obd_import *imp;
1156         unsigned int cur, worst;
1157         time_t now, worstt;
1158         struct dhms ts;
1159         int i;
1160
1161         LASSERT(obd != NULL);
1162         LPROCFS_CLIMP_CHECK(obd);
1163         imp = obd->u.cli.cl_import;
1164
1165         now = cfs_time_current_sec();
1166
1167         /* Some network health info for kicks */
1168         s2dhms(&ts, now - imp->imp_last_reply_time);
1169         seq_printf(m, "%-10s : %ld, "DHMS_FMT" ago\n",
1170                    "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
1171
1172         cur = at_get(&imp->imp_at.iat_net_latency);
1173         worst = imp->imp_at.iat_net_latency.at_worst_ever;
1174         worstt = imp->imp_at.iat_net_latency.at_worst_time;
1175         s2dhms(&ts, now - worstt);
1176         seq_printf(m, "%-10s : cur %3u  worst %3u (at %ld, "DHMS_FMT" ago) ",
1177                    "network", cur, worst, worstt, DHMS_VARS(&ts));
1178         lprocfs_seq_at_hist_helper(m, &imp->imp_at.iat_net_latency);
1179
1180         for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
1181                 if (imp->imp_at.iat_portal[i] == 0)
1182                         break;
1183                 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
1184                 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
1185                 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
1186                 s2dhms(&ts, now - worstt);
1187                 seq_printf(m, "portal %-2d  : cur %3u  worst %3u (at %ld, "
1188                            DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
1189                            cur, worst, worstt, DHMS_VARS(&ts));
1190                 lprocfs_seq_at_hist_helper(m, &imp->imp_at.iat_service_estimate[i]);
1191         }
1192
1193         LPROCFS_CLIMP_EXIT(obd);
1194         return 0;
1195 }
1196 EXPORT_SYMBOL(lprocfs_timeouts_seq_show);
1197
1198 int lprocfs_connect_flags_seq_show(struct seq_file *m, void *data)
1199 {
1200         struct obd_device *obd = data;
1201         __u64 flags;
1202
1203         LPROCFS_CLIMP_CHECK(obd);
1204         flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
1205         seq_printf(m, "flags="LPX64"\n", flags);
1206         obd_connect_seq_flags2str(m, flags, "\n");
1207         seq_printf(m, "\n");
1208         LPROCFS_CLIMP_EXIT(obd);
1209         return 0;
1210 }
1211 EXPORT_SYMBOL(lprocfs_connect_flags_seq_show);
1212
1213 int
1214 lprocfs_obd_setup(struct obd_device *obd)
1215 {
1216         int rc = 0;
1217
1218         LASSERT(obd != NULL);
1219         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
1220         LASSERT(obd->obd_type->typ_procroot != NULL);
1221
1222         obd->obd_proc_entry = lprocfs_seq_register(obd->obd_name,
1223                                                    obd->obd_type->typ_procroot,
1224                                                    obd->obd_vars, obd);
1225         if (IS_ERR(obd->obd_proc_entry)) {
1226                 rc = PTR_ERR(obd->obd_proc_entry);
1227                 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
1228                 obd->obd_proc_entry = NULL;
1229         }
1230         return rc;
1231 }
1232 EXPORT_SYMBOL(lprocfs_obd_setup);
1233
1234 int lprocfs_obd_cleanup(struct obd_device *obd)
1235 {
1236         if (!obd)
1237                 return -EINVAL;
1238         if (obd->obd_proc_exports_entry) {
1239                 /* Should be no exports left */
1240                 lprocfs_remove(&obd->obd_proc_exports_entry);
1241                 obd->obd_proc_exports_entry = NULL;
1242         }
1243         if (obd->obd_proc_entry) {
1244                 lprocfs_remove(&obd->obd_proc_entry);
1245                 obd->obd_proc_entry = NULL;
1246         }
1247         return 0;
1248 }
1249 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1250
1251 int lprocfs_stats_alloc_one(struct lprocfs_stats *stats, unsigned int cpuid)
1252 {
1253         struct lprocfs_counter  *cntr;
1254         unsigned int            percpusize;
1255         int                     rc = -ENOMEM;
1256         unsigned long           flags = 0;
1257         int                     i;
1258
1259         LASSERT(stats->ls_percpu[cpuid] == NULL);
1260         LASSERT((stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU) == 0);
1261
1262         percpusize = lprocfs_stats_counter_size(stats);
1263         LIBCFS_ALLOC_ATOMIC(stats->ls_percpu[cpuid], percpusize);
1264         if (stats->ls_percpu[cpuid] != NULL) {
1265                 rc = 0;
1266                 if (unlikely(stats->ls_biggest_alloc_num <= cpuid)) {
1267                         if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE)
1268                                 spin_lock_irqsave(&stats->ls_lock, flags);
1269                         else
1270                                 spin_lock(&stats->ls_lock);
1271                         if (stats->ls_biggest_alloc_num <= cpuid)
1272                                 stats->ls_biggest_alloc_num = cpuid + 1;
1273                         if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) {
1274                                 spin_unlock_irqrestore(&stats->ls_lock, flags);
1275                         } else {
1276                                 spin_unlock(&stats->ls_lock);
1277                         }
1278                 }
1279                 /* initialize the ls_percpu[cpuid] non-zero counter */
1280                 for (i = 0; i < stats->ls_num; ++i) {
1281                         cntr = lprocfs_stats_counter_get(stats, cpuid, i);
1282                         cntr->lc_min = LC_MIN_INIT;
1283                 }
1284         }
1285         return rc;
1286 }
1287 EXPORT_SYMBOL(lprocfs_stats_alloc_one);
1288
1289 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
1290                                           enum lprocfs_stats_flags flags)
1291 {
1292         struct lprocfs_stats    *stats;
1293         unsigned int            num_entry;
1294         unsigned int            percpusize = 0;
1295         int                     i;
1296
1297         if (num == 0)
1298                 return NULL;
1299
1300         if (lprocfs_no_percpu_stats != 0)
1301                 flags |= LPROCFS_STATS_FLAG_NOPERCPU;
1302
1303         if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
1304                 num_entry = 1;
1305         else
1306                 num_entry = num_possible_cpus();
1307
1308         /* alloc percpu pointers for all possible cpu slots */
1309         LIBCFS_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_entry]));
1310         if (stats == NULL)
1311                 return NULL;
1312
1313         stats->ls_num = num;
1314         stats->ls_flags = flags;
1315         spin_lock_init(&stats->ls_lock);
1316
1317         /* alloc num of counter headers */
1318         LIBCFS_ALLOC(stats->ls_cnt_header,
1319                      stats->ls_num * sizeof(struct lprocfs_counter_header));
1320         if (stats->ls_cnt_header == NULL)
1321                 goto fail;
1322
1323         if ((flags & LPROCFS_STATS_FLAG_NOPERCPU) != 0) {
1324                 /* contains only one set counters */
1325                 percpusize = lprocfs_stats_counter_size(stats);
1326                 LIBCFS_ALLOC_ATOMIC(stats->ls_percpu[0], percpusize);
1327                 if (stats->ls_percpu[0] == NULL)
1328                         goto fail;
1329                 stats->ls_biggest_alloc_num = 1;
1330         } else if ((flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0) {
1331                 /* alloc all percpu data, currently only obd_memory use this */
1332                 for (i = 0; i < num_entry; ++i)
1333                         if (lprocfs_stats_alloc_one(stats, i) < 0)
1334                                 goto fail;
1335         }
1336
1337         return stats;
1338
1339 fail:
1340         lprocfs_free_stats(&stats);
1341         return NULL;
1342 }
1343 EXPORT_SYMBOL(lprocfs_alloc_stats);
1344
1345 void lprocfs_free_stats(struct lprocfs_stats **statsh)
1346 {
1347         struct lprocfs_stats *stats = *statsh;
1348         unsigned int num_entry;
1349         unsigned int percpusize;
1350         unsigned int i;
1351
1352         if (stats == NULL || stats->ls_num == 0)
1353                 return;
1354         *statsh = NULL;
1355
1356         if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1357                 num_entry = 1;
1358         else
1359                 num_entry = num_possible_cpus();
1360
1361         percpusize = lprocfs_stats_counter_size(stats);
1362         for (i = 0; i < num_entry; i++)
1363                 if (stats->ls_percpu[i] != NULL)
1364                         LIBCFS_FREE(stats->ls_percpu[i], percpusize);
1365         if (stats->ls_cnt_header != NULL)
1366                 LIBCFS_FREE(stats->ls_cnt_header, stats->ls_num *
1367                                         sizeof(struct lprocfs_counter_header));
1368         LIBCFS_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_entry]));
1369 }
1370 EXPORT_SYMBOL(lprocfs_free_stats);
1371
1372 void lprocfs_clear_stats(struct lprocfs_stats *stats)
1373 {
1374         struct lprocfs_counter          *percpu_cntr;
1375         int                             i;
1376         int                             j;
1377         unsigned int                    num_entry;
1378         unsigned long                   flags = 0;
1379
1380         num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
1381
1382         for (i = 0; i < num_entry; i++) {
1383                 if (stats->ls_percpu[i] == NULL)
1384                         continue;
1385                 for (j = 0; j < stats->ls_num; j++) {
1386                         percpu_cntr = lprocfs_stats_counter_get(stats, i, j);
1387                         percpu_cntr->lc_count           = 0;
1388                         percpu_cntr->lc_min             = LC_MIN_INIT;
1389                         percpu_cntr->lc_max             = 0;
1390                         percpu_cntr->lc_sumsquare       = 0;
1391                         percpu_cntr->lc_sum             = 0;
1392                         if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE)
1393                                 percpu_cntr->lc_sum_irq = 0;
1394                 }
1395         }
1396
1397         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
1398 }
1399 EXPORT_SYMBOL(lprocfs_clear_stats);
1400
1401 static ssize_t lprocfs_stats_seq_write(struct file *file,
1402                                        const char __user *buf,
1403                                        size_t len, loff_t *off)
1404 {
1405         struct seq_file *seq = file->private_data;
1406         struct lprocfs_stats *stats = seq->private;
1407
1408         lprocfs_clear_stats(stats);
1409
1410         return len;
1411 }
1412
1413 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
1414 {
1415         struct lprocfs_stats *stats = p->private;
1416
1417         return (*pos < stats->ls_num) ? pos : NULL;
1418 }
1419
1420 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1421 {
1422 }
1423
1424 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1425 {
1426         (*pos)++;
1427
1428         return lprocfs_stats_seq_start(p, pos);
1429 }
1430
1431 /* seq file export of one lprocfs counter */
1432 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1433 {
1434         struct lprocfs_stats            *stats  = p->private;
1435         struct lprocfs_counter_header   *hdr;
1436         struct lprocfs_counter           ctr;
1437         int                              idx    = *(loff_t *)v;
1438         int                              rc     = 0;
1439
1440         if (idx == 0) {
1441                 struct timeval now;
1442
1443                 do_gettimeofday(&now);
1444                 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1445                                 "snapshot_time", now.tv_sec, now.tv_usec);
1446                 if (rc < 0)
1447                         return rc;
1448         }
1449
1450         hdr = &stats->ls_cnt_header[idx];
1451         lprocfs_stats_collect(stats, idx, &ctr);
1452
1453         if (ctr.lc_count == 0)
1454                 goto out;
1455
1456         rc = seq_printf(p, "%-25s "LPD64" samples [%s]", hdr->lc_name,
1457                         ctr.lc_count, hdr->lc_units);
1458         if (rc < 0)
1459                 goto out;
1460
1461         if ((hdr->lc_config & LPROCFS_CNTR_AVGMINMAX) && ctr.lc_count > 0) {
1462                 rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1463                                 ctr.lc_min, ctr.lc_max, ctr.lc_sum);
1464                 if (rc < 0)
1465                         goto out;
1466                 if (hdr->lc_config & LPROCFS_CNTR_STDDEV)
1467                         rc = seq_printf(p, " "LPD64, ctr.lc_sumsquare);
1468                 if (rc < 0)
1469                         goto out;
1470         }
1471         rc = seq_printf(p, "\n");
1472 out:
1473         return (rc < 0) ? rc : 0;
1474 }
1475
1476 static const struct seq_operations lprocfs_stats_seq_sops = {
1477         .start  = lprocfs_stats_seq_start,
1478         .stop   = lprocfs_stats_seq_stop,
1479         .next   = lprocfs_stats_seq_next,
1480         .show   = lprocfs_stats_seq_show,
1481 };
1482
1483 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1484 {
1485         struct seq_file *seq;
1486         int rc;
1487
1488         rc = LPROCFS_ENTRY_CHECK(inode);
1489         if (rc < 0)
1490                 return rc;
1491
1492         rc = seq_open(file, &lprocfs_stats_seq_sops);
1493         if (rc)
1494                 return rc;
1495         seq = file->private_data;
1496         seq->private = PDE_DATA(inode);
1497         return 0;
1498 }
1499
1500 static const struct file_operations lprocfs_stats_seq_fops = {
1501         .owner   = THIS_MODULE,
1502         .open    = lprocfs_stats_seq_open,
1503         .read    = seq_read,
1504         .write   = lprocfs_stats_seq_write,
1505         .llseek  = seq_lseek,
1506         .release = lprocfs_seq_release,
1507 };
1508
1509 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1510                            struct lprocfs_stats *stats)
1511 {
1512         struct proc_dir_entry *entry;
1513         LASSERT(root != NULL);
1514
1515         entry = proc_create_data(name, 0644, root,
1516                                  &lprocfs_stats_seq_fops, stats);
1517         if (entry == NULL)
1518                 return -ENOMEM;
1519         return 0;
1520 }
1521 EXPORT_SYMBOL(lprocfs_register_stats);
1522
1523 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1524                           unsigned conf, const char *name, const char *units)
1525 {
1526         struct lprocfs_counter_header   *header;
1527         struct lprocfs_counter          *percpu_cntr;
1528         unsigned long                   flags = 0;
1529         unsigned int                    i;
1530         unsigned int                    num_cpu;
1531
1532         LASSERT(stats != NULL);
1533
1534         header = &stats->ls_cnt_header[index];
1535         LASSERTF(header != NULL, "Failed to allocate stats header:[%d]%s/%s\n",
1536                  index, name, units);
1537
1538         header->lc_config = conf;
1539         header->lc_name   = name;
1540         header->lc_units  = units;
1541
1542         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
1543         for (i = 0; i < num_cpu; ++i) {
1544                 if (stats->ls_percpu[i] == NULL)
1545                         continue;
1546                 percpu_cntr = lprocfs_stats_counter_get(stats, i, index);
1547                 percpu_cntr->lc_count           = 0;
1548                 percpu_cntr->lc_min             = LC_MIN_INIT;
1549                 percpu_cntr->lc_max             = 0;
1550                 percpu_cntr->lc_sumsquare       = 0;
1551                 percpu_cntr->lc_sum             = 0;
1552                 if ((stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0)
1553                         percpu_cntr->lc_sum_irq = 0;
1554         }
1555         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
1556 }
1557 EXPORT_SYMBOL(lprocfs_counter_init);
1558
1559 /* Note that we only init md counters for ops whose offset is less
1560  * than NUM_MD_STATS. This is explained in a comment in the definition
1561  * of struct md_ops. */
1562 #define LPROCFS_MD_OP_INIT(base, stats, op)                                    \
1563         do {                                                                   \
1564                 unsigned int _idx = base + MD_COUNTER_OFFSET(op);              \
1565                                                                                \
1566                 if (MD_COUNTER_OFFSET(op) < NUM_MD_STATS) {                    \
1567                         LASSERT(_idx < stats->ls_num);                         \
1568                         lprocfs_counter_init(stats, _idx, 0, #op, "reqs");     \
1569                 }                                                              \
1570         } while (0)
1571
1572 void lprocfs_init_mps_stats(int num_private_stats, struct lprocfs_stats *stats)
1573 {
1574         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1575         LPROCFS_MD_OP_INIT(num_private_stats, stats, null_inode);
1576         LPROCFS_MD_OP_INIT(num_private_stats, stats, find_cbdata);
1577         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1578         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1579         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1580         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1581         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1582         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1583         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1584         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1585         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1586         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1587         LPROCFS_MD_OP_INIT(num_private_stats, stats, fsync);
1588         LPROCFS_MD_OP_INIT(num_private_stats, stats, read_page);
1589         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1590         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1591         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1592         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1593         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1594         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1595         LPROCFS_MD_OP_INIT(num_private_stats, stats, update_lsm_md);
1596         LPROCFS_MD_OP_INIT(num_private_stats, stats, merge_attr);
1597         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1598         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1599         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1600         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1601         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1602         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1603         LPROCFS_MD_OP_INIT(num_private_stats, stats, unpack_capa);
1604         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1605         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1606         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1607 }
1608 EXPORT_SYMBOL(lprocfs_init_mps_stats);
1609
1610 int lprocfs_alloc_md_stats(struct obd_device *obd,
1611                            unsigned int num_private_stats)
1612 {
1613         struct lprocfs_stats *stats;
1614         unsigned int num_stats;
1615         int rc, i;
1616
1617         CLASSERT(offsetof(struct md_ops, MD_STATS_FIRST_OP) == 0);
1618         CLASSERT(_MD_COUNTER_OFFSET(MD_STATS_FIRST_OP) == 0);
1619         CLASSERT(_MD_COUNTER_OFFSET(MD_STATS_LAST_OP) > 0);
1620
1621         /* TODO Ensure that this function is only used where
1622          * appropriate by adding an assertion to the effect that
1623          * obd->obd_type->typ_md_ops is not NULL. We can't do this now
1624          * because mdt_procfs_init() uses this function to allocate
1625          * the stats backing /proc/fs/lustre/mdt/.../md_stats but the
1626          * mdt layer does not use the md_ops interface. This is
1627          * confusing and a waste of memory. See LU-2484.
1628          */
1629         LASSERT(obd->obd_proc_entry != NULL);
1630         LASSERT(obd->obd_md_stats == NULL);
1631         LASSERT(obd->obd_md_cntr_base == 0);
1632
1633         num_stats = NUM_MD_STATS + num_private_stats;
1634         stats = lprocfs_alloc_stats(num_stats, 0);
1635         if (stats == NULL)
1636                 return -ENOMEM;
1637
1638         lprocfs_init_mps_stats(num_private_stats, stats);
1639
1640         for (i = num_private_stats; i < num_stats; i++) {
1641                 if (stats->ls_cnt_header[i].lc_name == NULL) {
1642                         CERROR("Missing md_stat initializer md_op "
1643                                "operation at offset %d. Aborting.\n",
1644                                i - num_private_stats);
1645                         LBUG();
1646                 }
1647         }
1648
1649         rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
1650         if (rc < 0) {
1651                 lprocfs_free_stats(&stats);
1652         } else {
1653                 obd->obd_md_stats = stats;
1654                 obd->obd_md_cntr_base = num_private_stats;
1655         }
1656
1657         return rc;
1658 }
1659 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
1660
1661 void lprocfs_free_md_stats(struct obd_device *obd)
1662 {
1663         struct lprocfs_stats *stats = obd->obd_md_stats;
1664
1665         if (stats != NULL) {
1666                 obd->obd_md_stats = NULL;
1667                 obd->obd_md_cntr_base = 0;
1668                 lprocfs_free_stats(&stats);
1669         }
1670 }
1671 EXPORT_SYMBOL(lprocfs_free_md_stats);
1672
1673 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1674 {
1675         lprocfs_counter_init(ldlm_stats,
1676                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
1677                              0, "ldlm_enqueue", "reqs");
1678         lprocfs_counter_init(ldlm_stats,
1679                              LDLM_CONVERT - LDLM_FIRST_OPC,
1680                              0, "ldlm_convert", "reqs");
1681         lprocfs_counter_init(ldlm_stats,
1682                              LDLM_CANCEL - LDLM_FIRST_OPC,
1683                              0, "ldlm_cancel", "reqs");
1684         lprocfs_counter_init(ldlm_stats,
1685                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1686                              0, "ldlm_bl_callback", "reqs");
1687         lprocfs_counter_init(ldlm_stats,
1688                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1689                              0, "ldlm_cp_callback", "reqs");
1690         lprocfs_counter_init(ldlm_stats,
1691                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1692                              0, "ldlm_gl_callback", "reqs");
1693 }
1694 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
1695
1696 __s64 lprocfs_read_helper(struct lprocfs_counter *lc,
1697                           struct lprocfs_counter_header *header,
1698                           enum lprocfs_stats_flags flags,
1699                           enum lprocfs_fields_flags field)
1700 {
1701         __s64 ret = 0;
1702
1703         if (lc == NULL || header == NULL)
1704                 RETURN(0);
1705
1706         switch (field) {
1707                 case LPROCFS_FIELDS_FLAGS_CONFIG:
1708                         ret = header->lc_config;
1709                         break;
1710                 case LPROCFS_FIELDS_FLAGS_SUM:
1711                         ret = lc->lc_sum;
1712                         if ((flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0)
1713                                 ret += lc->lc_sum_irq;
1714                         break;
1715                 case LPROCFS_FIELDS_FLAGS_MIN:
1716                         ret = lc->lc_min;
1717                         break;
1718                 case LPROCFS_FIELDS_FLAGS_MAX:
1719                         ret = lc->lc_max;
1720                         break;
1721                 case LPROCFS_FIELDS_FLAGS_AVG:
1722                         ret = (lc->lc_max - lc->lc_min) / 2;
1723                         break;
1724                 case LPROCFS_FIELDS_FLAGS_SUMSQUARE:
1725                         ret = lc->lc_sumsquare;
1726                         break;
1727                 case LPROCFS_FIELDS_FLAGS_COUNT:
1728                         ret = lc->lc_count;
1729                         break;
1730                 default:
1731                         break;
1732         };
1733         RETURN(ret);
1734 }
1735 EXPORT_SYMBOL(lprocfs_read_helper);
1736
1737 int lprocfs_write_helper(const char __user *buffer, unsigned long count,
1738                          int *val)
1739 {
1740         return lprocfs_write_frac_helper(buffer, count, val, 1);
1741 }
1742 EXPORT_SYMBOL(lprocfs_write_helper);
1743
1744 int lprocfs_write_frac_helper(const char __user *buffer, unsigned long count,
1745                               int *val, int mult)
1746 {
1747         char kernbuf[20], *end, *pbuf;
1748
1749         if (count > (sizeof(kernbuf) - 1))
1750                 return -EINVAL;
1751
1752         if (copy_from_user(kernbuf, buffer, count))
1753                 return -EFAULT;
1754
1755         kernbuf[count] = '\0';
1756         pbuf = kernbuf;
1757         if (*pbuf == '-') {
1758                 mult = -mult;
1759                 pbuf++;
1760         }
1761
1762         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1763         if (pbuf == end)
1764                 return -EINVAL;
1765
1766         if (end != NULL && *end == '.') {
1767                 int temp_val, pow = 1;
1768                 int i;
1769
1770                 pbuf = end + 1;
1771                 if (strlen(pbuf) > 5)
1772                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
1773
1774                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1775
1776                 if (pbuf < end) {
1777                         for (i = 0; i < (end - pbuf); i++)
1778                                 pow *= 10;
1779
1780                         *val += temp_val / pow;
1781                 }
1782         }
1783         return 0;
1784 }
1785 EXPORT_SYMBOL(lprocfs_write_frac_helper);
1786
1787 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
1788                              int mult)
1789 {
1790         long decimal_val, frac_val;
1791         int prtn;
1792
1793         if (count < 10)
1794                 return -EINVAL;
1795
1796         decimal_val = val / mult;
1797         prtn = snprintf(buffer, count, "%ld", decimal_val);
1798         frac_val = val % mult;
1799
1800         if (prtn < (count - 4) && frac_val > 0) {
1801                 long temp_frac;
1802                 int i, temp_mult = 1, frac_bits = 0;
1803
1804                 temp_frac = frac_val * 10;
1805                 buffer[prtn++] = '.';
1806                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
1807                         /* only reserved 2 bits fraction */
1808                         buffer[prtn++] ='0';
1809                         temp_frac *= 10;
1810                         frac_bits++;
1811                 }
1812                 /*
1813                  * Need to think these cases :
1814                  *      1. #echo x.00 > /proc/xxx       output result : x
1815                  *      2. #echo x.0x > /proc/xxx       output result : x.0x
1816                  *      3. #echo x.x0 > /proc/xxx       output result : x.x
1817                  *      4. #echo x.xx > /proc/xxx       output result : x.xx
1818                  *      Only reserved 2 bits fraction.
1819                  */
1820                 for (i = 0; i < (5 - prtn); i++)
1821                         temp_mult *= 10;
1822
1823                 frac_bits = min((int)count - prtn, 3 - frac_bits);
1824                 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
1825                                  frac_val * temp_mult / mult);
1826
1827                 prtn--;
1828                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1829                         prtn--;
1830                         if (buffer[prtn] == '.') {
1831                                 prtn--;
1832                                 break;
1833                         }
1834                 }
1835                 prtn++;
1836         }
1837         buffer[prtn++] ='\n';
1838         return prtn;
1839 }
1840 EXPORT_SYMBOL(lprocfs_read_frac_helper);
1841
1842 int lprocfs_seq_read_frac_helper(struct seq_file *m, long val, int mult)
1843 {
1844         long decimal_val, frac_val;
1845
1846         decimal_val = val / mult;
1847         seq_printf(m, "%ld", decimal_val);
1848         frac_val = val % mult;
1849
1850         if (frac_val > 0) {
1851                 frac_val *= 100;
1852                 frac_val /= mult;
1853         }
1854         if (frac_val > 0) {
1855                 /* Three cases: x0, xx, 0x */
1856                 if ((frac_val % 10) != 0)
1857                         seq_printf(m, ".%ld", frac_val);
1858                 else
1859                         seq_printf(m, ".%ld", frac_val / 10);
1860         }
1861
1862         seq_printf(m, "\n");
1863         return 0;
1864 }
1865 EXPORT_SYMBOL(lprocfs_seq_read_frac_helper);
1866
1867 int lprocfs_write_u64_helper(const char __user *buffer, unsigned long count,
1868                              __u64 *val)
1869 {
1870         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1871 }
1872 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1873
1874 int lprocfs_write_frac_u64_helper(const char __user *buffer,
1875                                   unsigned long count,
1876                                   __u64 *val, int mult)
1877 {
1878         char kernbuf[22], *end, *pbuf;
1879         __u64 whole, frac = 0, units;
1880         unsigned frac_d = 1;
1881
1882         if (count > (sizeof(kernbuf) - 1))
1883                 return -EINVAL;
1884
1885         if (copy_from_user(kernbuf, buffer, count))
1886                 return -EFAULT;
1887
1888         kernbuf[count] = '\0';
1889         pbuf = kernbuf;
1890         if (*pbuf == '-') {
1891                 mult = -mult;
1892                 pbuf++;
1893         }
1894
1895         whole = simple_strtoull(pbuf, &end, 10);
1896         if (pbuf == end)
1897                 return -EINVAL;
1898
1899         if (end != NULL && *end == '.') {
1900                 int i;
1901                 pbuf = end + 1;
1902
1903                 /* need to limit frac_d to a __u32 */
1904                 if (strlen(pbuf) > 10)
1905                         pbuf[10] = '\0';
1906
1907                 frac = simple_strtoull(pbuf, &end, 10);
1908                 /* count decimal places */
1909                 for (i = 0; i < (end - pbuf); i++)
1910                         frac_d *= 10;
1911         }
1912
1913         units = 1;
1914         if (end != NULL) {
1915                 switch (*end) {
1916                 case 'p': case 'P':
1917                         units <<= 10;
1918                 case 't': case 'T':
1919                         units <<= 10;
1920                 case 'g': case 'G':
1921                         units <<= 10;
1922                 case 'm': case 'M':
1923                         units <<= 10;
1924                 case 'k': case 'K':
1925                         units <<= 10;
1926                 }
1927         }
1928         /* Specified units override the multiplier */
1929         if (units > 1)
1930                 mult = mult < 0 ? -units : units;
1931
1932         frac *= mult;
1933         do_div(frac, frac_d);
1934         *val = whole * mult + frac;
1935         return 0;
1936 }
1937 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
1938
1939 static char *lprocfs_strnstr(const char *s1, const char *s2, size_t len)
1940 {
1941         size_t l2;
1942
1943         l2 = strlen(s2);
1944         if (!l2)
1945                 return (char *)s1;
1946         while (len >= l2) {
1947                 len--;
1948                 if (!memcmp(s1, s2, l2))
1949                         return (char *)s1;
1950                 s1++;
1951         }
1952         return NULL;
1953 }
1954
1955 /**
1956  * Find the string \a name in the input \a buffer, and return a pointer to the
1957  * value immediately following \a name, reducing \a count appropriately.
1958  * If \a name is not found the original \a buffer is returned.
1959  */
1960 char *lprocfs_find_named_value(const char *buffer, const char *name,
1961                                 size_t *count)
1962 {
1963         char *val;
1964         size_t buflen = *count;
1965
1966         /* there is no strnstr() in rhel5 and ubuntu kernels */
1967         val = lprocfs_strnstr(buffer, name, buflen);
1968         if (val == NULL)
1969                 return (char *)buffer;
1970
1971         val += strlen(name);                             /* skip prefix */
1972         while (val < buffer + buflen && isspace(*val)) /* skip separator */
1973                 val++;
1974
1975         *count = 0;
1976         while (val < buffer + buflen && isalnum(*val)) {
1977                 ++*count;
1978                 ++val;
1979         }
1980
1981         return val - *count;
1982 }
1983 EXPORT_SYMBOL(lprocfs_find_named_value);
1984
1985 int lprocfs_seq_create(struct proc_dir_entry *parent,
1986                        const char *name,
1987                        mode_t mode,
1988                        const struct file_operations *seq_fops,
1989                        void *data)
1990 {
1991         struct proc_dir_entry *entry;
1992         ENTRY;
1993
1994         /* Disallow secretly (un)writable entries. */
1995         LASSERT((seq_fops->write == NULL) == ((mode & 0222) == 0));
1996
1997         entry = proc_create_data(name, mode, parent, seq_fops, data);
1998
1999         if (entry == NULL)
2000                 RETURN(-ENOMEM);
2001
2002         RETURN(0);
2003 }
2004 EXPORT_SYMBOL(lprocfs_seq_create);
2005
2006 int lprocfs_obd_seq_create(struct obd_device *dev,
2007                            const char *name,
2008                            mode_t mode,
2009                            const struct file_operations *seq_fops,
2010                            void *data)
2011 {
2012         return (lprocfs_seq_create(dev->obd_proc_entry, name,
2013                                    mode, seq_fops, data));
2014 }
2015 EXPORT_SYMBOL(lprocfs_obd_seq_create);
2016
2017 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
2018 {
2019         if (value >= OBD_HIST_MAX)
2020                 value = OBD_HIST_MAX - 1;
2021
2022         spin_lock(&oh->oh_lock);
2023         oh->oh_buckets[value]++;
2024         spin_unlock(&oh->oh_lock);
2025 }
2026 EXPORT_SYMBOL(lprocfs_oh_tally);
2027
2028 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
2029 {
2030         unsigned int val = 0;
2031
2032         if (likely(value != 0))
2033                 val = min(fls(value - 1), OBD_HIST_MAX);
2034
2035         lprocfs_oh_tally(oh, val);
2036 }
2037 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
2038
2039 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
2040 {
2041         unsigned long ret = 0;
2042         int i;
2043
2044         for (i = 0; i < OBD_HIST_MAX; i++)
2045                 ret +=  oh->oh_buckets[i];
2046         return ret;
2047 }
2048 EXPORT_SYMBOL(lprocfs_oh_sum);
2049
2050 void lprocfs_oh_clear(struct obd_histogram *oh)
2051 {
2052         spin_lock(&oh->oh_lock);
2053         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
2054         spin_unlock(&oh->oh_lock);
2055 }
2056 EXPORT_SYMBOL(lprocfs_oh_clear);
2057
2058 int lprocfs_obd_rd_max_pages_per_rpc(char *page, char **start, off_t off,
2059                                      int count, int *eof, void *data)
2060 {
2061         struct obd_device *dev = data;
2062         struct client_obd *cli = &dev->u.cli;
2063         int rc;
2064
2065         spin_lock(&cli->cl_loi_list_lock);
2066         rc = snprintf(page, count, "%d\n", cli->cl_max_pages_per_rpc);
2067         spin_unlock(&cli->cl_loi_list_lock);
2068
2069         return rc;
2070 }
2071 EXPORT_SYMBOL(lprocfs_obd_rd_max_pages_per_rpc);
2072
2073 int lprocfs_obd_max_pages_per_rpc_seq_show(struct seq_file *m, void *data)
2074 {
2075         struct obd_device *dev = data;
2076         struct client_obd *cli = &dev->u.cli;
2077         int rc;
2078
2079         spin_lock(&cli->cl_loi_list_lock);
2080         rc = seq_printf(m, "%d\n", cli->cl_max_pages_per_rpc);
2081         spin_unlock(&cli->cl_loi_list_lock);
2082         return rc;
2083 }
2084 EXPORT_SYMBOL(lprocfs_obd_max_pages_per_rpc_seq_show);
2085
2086 int lprocfs_wr_root_squash(const char __user *buffer, unsigned long count,
2087                            struct root_squash_info *squash, char *name)
2088 {
2089         int rc;
2090         char kernbuf[64], *tmp, *errmsg;
2091         unsigned long uid, gid;
2092         ENTRY;
2093
2094         if (count >= sizeof(kernbuf)) {
2095                 errmsg = "string too long";
2096                 GOTO(failed_noprint, rc = -EINVAL);
2097         }
2098         if (copy_from_user(kernbuf, buffer, count)) {
2099                 errmsg = "bad address";
2100                 GOTO(failed_noprint, rc = -EFAULT);
2101         }
2102         kernbuf[count] = '\0';
2103
2104         /* look for uid gid separator */
2105         tmp = strchr(kernbuf, ':');
2106         if (tmp == NULL) {
2107                 errmsg = "needs uid:gid format";
2108                 GOTO(failed, rc = -EINVAL);
2109         }
2110         *tmp = '\0';
2111         tmp++;
2112
2113         /* parse uid */
2114         if (kstrtoul(kernbuf, 0, &uid) != 0) {
2115                 errmsg = "bad uid";
2116                 GOTO(failed, rc = -EINVAL);
2117         }
2118
2119         /* parse gid */
2120         if (kstrtoul(tmp, 0, &gid) != 0) {
2121                 errmsg = "bad gid";
2122                 GOTO(failed, rc = -EINVAL);
2123         }
2124
2125         squash->rsi_uid = uid;
2126         squash->rsi_gid = gid;
2127
2128         LCONSOLE_INFO("%s: root_squash is set to %u:%u\n",
2129                       name, squash->rsi_uid, squash->rsi_gid);
2130         RETURN(count);
2131
2132 failed:
2133         if (tmp != NULL) {
2134                 tmp--;
2135                 *tmp = ':';
2136         }
2137         CWARN("%s: failed to set root_squash to \"%s\", %s, rc = %d\n",
2138               name, kernbuf, errmsg, rc);
2139         RETURN(rc);
2140 failed_noprint:
2141         CWARN("%s: failed to set root_squash due to %s, rc = %d\n",
2142               name, errmsg, rc);
2143         RETURN(rc);
2144 }
2145 EXPORT_SYMBOL(lprocfs_wr_root_squash);
2146
2147
2148 int lprocfs_wr_nosquash_nids(const char __user *buffer, unsigned long count,
2149                              struct root_squash_info *squash, char *name)
2150 {
2151         int rc;
2152         char *kernbuf = NULL;
2153         char *errmsg;
2154         struct list_head tmp;
2155         ENTRY;
2156
2157         if (count > 4096) {
2158                 errmsg = "string too long";
2159                 GOTO(failed, rc = -EINVAL);
2160         }
2161
2162         OBD_ALLOC(kernbuf, count + 1);
2163         if (kernbuf == NULL) {
2164                 errmsg = "no memory";
2165                 GOTO(failed, rc = -ENOMEM);
2166         }
2167         if (copy_from_user(kernbuf, buffer, count)) {
2168                 errmsg = "bad address";
2169                 GOTO(failed, rc = -EFAULT);
2170         }
2171         kernbuf[count] = '\0';
2172
2173         if (count > 0 && kernbuf[count - 1] == '\n')
2174                 kernbuf[count - 1] = '\0';
2175
2176         if (strcmp(kernbuf, "NONE") == 0 || strcmp(kernbuf, "clear") == 0) {
2177                 /* empty string is special case */
2178                 down_write(&squash->rsi_sem);
2179                 if (!list_empty(&squash->rsi_nosquash_nids))
2180                         cfs_free_nidlist(&squash->rsi_nosquash_nids);
2181                 up_write(&squash->rsi_sem);
2182                 LCONSOLE_INFO("%s: nosquash_nids is cleared\n", name);
2183                 OBD_FREE(kernbuf, count + 1);
2184                 RETURN(count);
2185         }
2186
2187         INIT_LIST_HEAD(&tmp);
2188         if (cfs_parse_nidlist(kernbuf, count, &tmp) <= 0) {
2189                 errmsg = "can't parse";
2190                 GOTO(failed, rc = -EINVAL);
2191         }
2192         LCONSOLE_INFO("%s: nosquash_nids set to %s\n",
2193                       name, kernbuf);
2194         OBD_FREE(kernbuf, count + 1);
2195         kernbuf = NULL;
2196
2197         down_write(&squash->rsi_sem);
2198         if (!list_empty(&squash->rsi_nosquash_nids))
2199                 cfs_free_nidlist(&squash->rsi_nosquash_nids);
2200         list_splice(&tmp, &squash->rsi_nosquash_nids);
2201         up_write(&squash->rsi_sem);
2202
2203         RETURN(count);
2204
2205 failed:
2206         if (kernbuf) {
2207                 CWARN("%s: failed to set nosquash_nids to \"%s\", %s rc = %d\n",
2208                       name, kernbuf, errmsg, rc);
2209                 OBD_FREE(kernbuf, count + 1);
2210         } else {
2211                 CWARN("%s: failed to set nosquash_nids due to %s rc = %d\n",
2212                       name, errmsg, rc);
2213         }
2214         RETURN(rc);
2215 }
2216 EXPORT_SYMBOL(lprocfs_wr_nosquash_nids);
2217
2218 #endif /* CONFIG_PROC_FS*/