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