Whamcloud - gitweb
e38c39dabad073ba426178272b879bfab2fc5524
[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, 2013, 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 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 *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 *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 *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, const char *buf,
1395                                        size_t len, loff_t *off)
1396 {
1397         struct seq_file *seq = file->private_data;
1398         struct lprocfs_stats *stats = seq->private;
1399
1400         lprocfs_clear_stats(stats);
1401
1402         return len;
1403 }
1404
1405 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
1406 {
1407         struct lprocfs_stats *stats = p->private;
1408
1409         return (*pos < stats->ls_num) ? pos : NULL;
1410 }
1411
1412 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1413 {
1414 }
1415
1416 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1417 {
1418         (*pos)++;
1419
1420         return lprocfs_stats_seq_start(p, pos);
1421 }
1422
1423 /* seq file export of one lprocfs counter */
1424 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1425 {
1426         struct lprocfs_stats            *stats  = p->private;
1427         struct lprocfs_counter_header   *hdr;
1428         struct lprocfs_counter           ctr;
1429         int                              idx    = *(loff_t *)v;
1430         int                              rc     = 0;
1431
1432         if (idx == 0) {
1433                 struct timeval now;
1434
1435                 do_gettimeofday(&now);
1436                 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1437                                 "snapshot_time", now.tv_sec, now.tv_usec);
1438                 if (rc < 0)
1439                         return rc;
1440         }
1441
1442         hdr = &stats->ls_cnt_header[idx];
1443         lprocfs_stats_collect(stats, idx, &ctr);
1444
1445         if (ctr.lc_count == 0)
1446                 goto out;
1447
1448         rc = seq_printf(p, "%-25s "LPD64" samples [%s]", hdr->lc_name,
1449                         ctr.lc_count, hdr->lc_units);
1450         if (rc < 0)
1451                 goto out;
1452
1453         if ((hdr->lc_config & LPROCFS_CNTR_AVGMINMAX) && ctr.lc_count > 0) {
1454                 rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1455                                 ctr.lc_min, ctr.lc_max, ctr.lc_sum);
1456                 if (rc < 0)
1457                         goto out;
1458                 if (hdr->lc_config & LPROCFS_CNTR_STDDEV)
1459                         rc = seq_printf(p, " "LPD64, ctr.lc_sumsquare);
1460                 if (rc < 0)
1461                         goto out;
1462         }
1463         rc = seq_printf(p, "\n");
1464 out:
1465         return (rc < 0) ? rc : 0;
1466 }
1467
1468 struct seq_operations lprocfs_stats_seq_sops = {
1469         .start  = lprocfs_stats_seq_start,
1470         .stop   = lprocfs_stats_seq_stop,
1471         .next   = lprocfs_stats_seq_next,
1472         .show   = lprocfs_stats_seq_show,
1473 };
1474
1475 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1476 {
1477         struct seq_file *seq;
1478         int rc;
1479
1480 #ifndef HAVE_ONLY_PROCFS_SEQ
1481         if (LPROCFS_ENTRY_CHECK(PDE(inode)))
1482                 return -ENOENT;
1483 #endif
1484         rc = seq_open(file, &lprocfs_stats_seq_sops);
1485         if (rc)
1486                 return rc;
1487         seq = file->private_data;
1488         seq->private = PDE_DATA(inode);
1489         return 0;
1490 }
1491
1492 struct file_operations lprocfs_stats_seq_fops = {
1493         .owner   = THIS_MODULE,
1494         .open    = lprocfs_stats_seq_open,
1495         .read    = seq_read,
1496         .write   = lprocfs_stats_seq_write,
1497         .llseek  = seq_lseek,
1498         .release = lprocfs_seq_release,
1499 };
1500
1501 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1502                            struct lprocfs_stats *stats)
1503 {
1504         struct proc_dir_entry *entry;
1505         LASSERT(root != NULL);
1506
1507         entry = proc_create_data(name, 0644, root,
1508                                  &lprocfs_stats_seq_fops, stats);
1509         if (entry == NULL)
1510                 return -ENOMEM;
1511         return 0;
1512 }
1513 EXPORT_SYMBOL(lprocfs_register_stats);
1514
1515 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1516                           unsigned conf, const char *name, const char *units)
1517 {
1518         struct lprocfs_counter_header   *header;
1519         struct lprocfs_counter          *percpu_cntr;
1520         unsigned long                   flags = 0;
1521         unsigned int                    i;
1522         unsigned int                    num_cpu;
1523
1524         LASSERT(stats != NULL);
1525
1526         header = &stats->ls_cnt_header[index];
1527         LASSERTF(header != NULL, "Failed to allocate stats header:[%d]%s/%s\n",
1528                  index, name, units);
1529
1530         header->lc_config = conf;
1531         header->lc_name   = name;
1532         header->lc_units  = units;
1533
1534         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
1535         for (i = 0; i < num_cpu; ++i) {
1536                 if (stats->ls_percpu[i] == NULL)
1537                         continue;
1538                 percpu_cntr = lprocfs_stats_counter_get(stats, i, index);
1539                 percpu_cntr->lc_count           = 0;
1540                 percpu_cntr->lc_min             = LC_MIN_INIT;
1541                 percpu_cntr->lc_max             = 0;
1542                 percpu_cntr->lc_sumsquare       = 0;
1543                 percpu_cntr->lc_sum             = 0;
1544                 if ((stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0)
1545                         percpu_cntr->lc_sum_irq = 0;
1546         }
1547         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
1548 }
1549 EXPORT_SYMBOL(lprocfs_counter_init);
1550
1551 /* Note that we only init md counters for ops whose offset is less
1552  * than NUM_MD_STATS. This is explained in a comment in the definition
1553  * of struct md_ops. */
1554 #define LPROCFS_MD_OP_INIT(base, stats, op)                                    \
1555         do {                                                                   \
1556                 unsigned int _idx = base + MD_COUNTER_OFFSET(op);              \
1557                                                                                \
1558                 if (MD_COUNTER_OFFSET(op) < NUM_MD_STATS) {                    \
1559                         LASSERT(_idx < stats->ls_num);                         \
1560                         lprocfs_counter_init(stats, _idx, 0, #op, "reqs");     \
1561                 }                                                              \
1562         } while (0)
1563
1564 void lprocfs_init_mps_stats(int num_private_stats, struct lprocfs_stats *stats)
1565 {
1566         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1567         LPROCFS_MD_OP_INIT(num_private_stats, stats, null_inode);
1568         LPROCFS_MD_OP_INIT(num_private_stats, stats, find_cbdata);
1569         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1570         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1571         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1572         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1573         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1574         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1575         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1576         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1577         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1578         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1579         LPROCFS_MD_OP_INIT(num_private_stats, stats, fsync);
1580         LPROCFS_MD_OP_INIT(num_private_stats, stats, read_page);
1581         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1582         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1583         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1584         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1585         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1586         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1587         LPROCFS_MD_OP_INIT(num_private_stats, stats, update_lsm_md);
1588         LPROCFS_MD_OP_INIT(num_private_stats, stats, merge_attr);
1589         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1590         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1591         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1592         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1593         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1594         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1595         LPROCFS_MD_OP_INIT(num_private_stats, stats, unpack_capa);
1596         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1597         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1598         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1599 }
1600 EXPORT_SYMBOL(lprocfs_init_mps_stats);
1601
1602 int lprocfs_alloc_md_stats(struct obd_device *obd,
1603                            unsigned int num_private_stats)
1604 {
1605         struct lprocfs_stats *stats;
1606         unsigned int num_stats;
1607         int rc, i;
1608
1609         CLASSERT(offsetof(struct md_ops, MD_STATS_FIRST_OP) == 0);
1610         CLASSERT(_MD_COUNTER_OFFSET(MD_STATS_FIRST_OP) == 0);
1611         CLASSERT(_MD_COUNTER_OFFSET(MD_STATS_LAST_OP) > 0);
1612
1613         /* TODO Ensure that this function is only used where
1614          * appropriate by adding an assertion to the effect that
1615          * obd->obd_type->typ_md_ops is not NULL. We can't do this now
1616          * because mdt_procfs_init() uses this function to allocate
1617          * the stats backing /proc/fs/lustre/mdt/.../md_stats but the
1618          * mdt layer does not use the md_ops interface. This is
1619          * confusing and a waste of memory. See LU-2484.
1620          */
1621         LASSERT(obd->obd_proc_entry != NULL);
1622         LASSERT(obd->obd_md_stats == NULL);
1623         LASSERT(obd->obd_md_cntr_base == 0);
1624
1625         num_stats = NUM_MD_STATS + num_private_stats;
1626         stats = lprocfs_alloc_stats(num_stats, 0);
1627         if (stats == NULL)
1628                 return -ENOMEM;
1629
1630         lprocfs_init_mps_stats(num_private_stats, stats);
1631
1632         for (i = num_private_stats; i < num_stats; i++) {
1633                 if (stats->ls_cnt_header[i].lc_name == NULL) {
1634                         CERROR("Missing md_stat initializer md_op "
1635                                "operation at offset %d. Aborting.\n",
1636                                i - num_private_stats);
1637                         LBUG();
1638                 }
1639         }
1640
1641         rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
1642         if (rc < 0) {
1643                 lprocfs_free_stats(&stats);
1644         } else {
1645                 obd->obd_md_stats = stats;
1646                 obd->obd_md_cntr_base = num_private_stats;
1647         }
1648
1649         return rc;
1650 }
1651 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
1652
1653 void lprocfs_free_md_stats(struct obd_device *obd)
1654 {
1655         struct lprocfs_stats *stats = obd->obd_md_stats;
1656
1657         if (stats != NULL) {
1658                 obd->obd_md_stats = NULL;
1659                 obd->obd_md_cntr_base = 0;
1660                 lprocfs_free_stats(&stats);
1661         }
1662 }
1663 EXPORT_SYMBOL(lprocfs_free_md_stats);
1664
1665 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1666 {
1667         lprocfs_counter_init(ldlm_stats,
1668                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
1669                              0, "ldlm_enqueue", "reqs");
1670         lprocfs_counter_init(ldlm_stats,
1671                              LDLM_CONVERT - LDLM_FIRST_OPC,
1672                              0, "ldlm_convert", "reqs");
1673         lprocfs_counter_init(ldlm_stats,
1674                              LDLM_CANCEL - LDLM_FIRST_OPC,
1675                              0, "ldlm_cancel", "reqs");
1676         lprocfs_counter_init(ldlm_stats,
1677                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1678                              0, "ldlm_bl_callback", "reqs");
1679         lprocfs_counter_init(ldlm_stats,
1680                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1681                              0, "ldlm_cp_callback", "reqs");
1682         lprocfs_counter_init(ldlm_stats,
1683                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1684                              0, "ldlm_gl_callback", "reqs");
1685 }
1686 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
1687
1688 __s64 lprocfs_read_helper(struct lprocfs_counter *lc,
1689                           struct lprocfs_counter_header *header,
1690                           enum lprocfs_stats_flags flags,
1691                           enum lprocfs_fields_flags field)
1692 {
1693         __s64 ret = 0;
1694
1695         if (lc == NULL || header == NULL)
1696                 RETURN(0);
1697
1698         switch (field) {
1699                 case LPROCFS_FIELDS_FLAGS_CONFIG:
1700                         ret = header->lc_config;
1701                         break;
1702                 case LPROCFS_FIELDS_FLAGS_SUM:
1703                         ret = lc->lc_sum;
1704                         if ((flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0)
1705                                 ret += lc->lc_sum_irq;
1706                         break;
1707                 case LPROCFS_FIELDS_FLAGS_MIN:
1708                         ret = lc->lc_min;
1709                         break;
1710                 case LPROCFS_FIELDS_FLAGS_MAX:
1711                         ret = lc->lc_max;
1712                         break;
1713                 case LPROCFS_FIELDS_FLAGS_AVG:
1714                         ret = (lc->lc_max - lc->lc_min) / 2;
1715                         break;
1716                 case LPROCFS_FIELDS_FLAGS_SUMSQUARE:
1717                         ret = lc->lc_sumsquare;
1718                         break;
1719                 case LPROCFS_FIELDS_FLAGS_COUNT:
1720                         ret = lc->lc_count;
1721                         break;
1722                 default:
1723                         break;
1724         };
1725         RETURN(ret);
1726 }
1727 EXPORT_SYMBOL(lprocfs_read_helper);
1728
1729 int lprocfs_write_helper(const char *buffer, unsigned long count,
1730                          int *val)
1731 {
1732         return lprocfs_write_frac_helper(buffer, count, val, 1);
1733 }
1734 EXPORT_SYMBOL(lprocfs_write_helper);
1735
1736 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1737                               int *val, int mult)
1738 {
1739         char kernbuf[20], *end, *pbuf;
1740
1741         if (count > (sizeof(kernbuf) - 1))
1742                 return -EINVAL;
1743
1744         if (copy_from_user(kernbuf, buffer, count))
1745                 return -EFAULT;
1746
1747         kernbuf[count] = '\0';
1748         pbuf = kernbuf;
1749         if (*pbuf == '-') {
1750                 mult = -mult;
1751                 pbuf++;
1752         }
1753
1754         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1755         if (pbuf == end)
1756                 return -EINVAL;
1757
1758         if (end != NULL && *end == '.') {
1759                 int temp_val, pow = 1;
1760                 int i;
1761
1762                 pbuf = end + 1;
1763                 if (strlen(pbuf) > 5)
1764                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
1765
1766                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1767
1768                 if (pbuf < end) {
1769                         for (i = 0; i < (end - pbuf); i++)
1770                                 pow *= 10;
1771
1772                         *val += temp_val / pow;
1773                 }
1774         }
1775         return 0;
1776 }
1777 EXPORT_SYMBOL(lprocfs_write_frac_helper);
1778
1779 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
1780                              int mult)
1781 {
1782         long decimal_val, frac_val;
1783         int prtn;
1784
1785         if (count < 10)
1786                 return -EINVAL;
1787
1788         decimal_val = val / mult;
1789         prtn = snprintf(buffer, count, "%ld", decimal_val);
1790         frac_val = val % mult;
1791
1792         if (prtn < (count - 4) && frac_val > 0) {
1793                 long temp_frac;
1794                 int i, temp_mult = 1, frac_bits = 0;
1795
1796                 temp_frac = frac_val * 10;
1797                 buffer[prtn++] = '.';
1798                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
1799                         /* only reserved 2 bits fraction */
1800                         buffer[prtn++] ='0';
1801                         temp_frac *= 10;
1802                         frac_bits++;
1803                 }
1804                 /*
1805                  * Need to think these cases :
1806                  *      1. #echo x.00 > /proc/xxx       output result : x
1807                  *      2. #echo x.0x > /proc/xxx       output result : x.0x
1808                  *      3. #echo x.x0 > /proc/xxx       output result : x.x
1809                  *      4. #echo x.xx > /proc/xxx       output result : x.xx
1810                  *      Only reserved 2 bits fraction.
1811                  */
1812                 for (i = 0; i < (5 - prtn); i++)
1813                         temp_mult *= 10;
1814
1815                 frac_bits = min((int)count - prtn, 3 - frac_bits);
1816                 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
1817                                  frac_val * temp_mult / mult);
1818
1819                 prtn--;
1820                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1821                         prtn--;
1822                         if (buffer[prtn] == '.') {
1823                                 prtn--;
1824                                 break;
1825                         }
1826                 }
1827                 prtn++;
1828         }
1829         buffer[prtn++] ='\n';
1830         return prtn;
1831 }
1832 EXPORT_SYMBOL(lprocfs_read_frac_helper);
1833
1834 int lprocfs_seq_read_frac_helper(struct seq_file *m, long val, int mult)
1835 {
1836         long decimal_val, frac_val;
1837
1838         decimal_val = val / mult;
1839         seq_printf(m, "%ld", decimal_val);
1840         frac_val = val % mult;
1841
1842         if (frac_val > 0) {
1843                 frac_val *= 100;
1844                 frac_val /= mult;
1845         }
1846         if (frac_val > 0) {
1847                 /* Three cases: x0, xx, 0x */
1848                 if ((frac_val % 10) != 0)
1849                         seq_printf(m, ".%ld", frac_val);
1850                 else
1851                         seq_printf(m, ".%ld", frac_val / 10);
1852         }
1853
1854         seq_printf(m, "\n");
1855         return 0;
1856 }
1857 EXPORT_SYMBOL(lprocfs_seq_read_frac_helper);
1858
1859 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1860 {
1861         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1862 }
1863 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1864
1865 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1866                               __u64 *val, int mult)
1867 {
1868         char kernbuf[22], *end, *pbuf;
1869         __u64 whole, frac = 0, units;
1870         unsigned frac_d = 1;
1871
1872         if (count > (sizeof(kernbuf) - 1))
1873                 return -EINVAL;
1874
1875         if (copy_from_user(kernbuf, buffer, count))
1876                 return -EFAULT;
1877
1878         kernbuf[count] = '\0';
1879         pbuf = kernbuf;
1880         if (*pbuf == '-') {
1881                 mult = -mult;
1882                 pbuf++;
1883         }
1884
1885         whole = simple_strtoull(pbuf, &end, 10);
1886         if (pbuf == end)
1887                 return -EINVAL;
1888
1889         if (end != NULL && *end == '.') {
1890                 int i;
1891                 pbuf = end + 1;
1892
1893                 /* need to limit frac_d to a __u32 */
1894                 if (strlen(pbuf) > 10)
1895                         pbuf[10] = '\0';
1896
1897                 frac = simple_strtoull(pbuf, &end, 10);
1898                 /* count decimal places */
1899                 for (i = 0; i < (end - pbuf); i++)
1900                         frac_d *= 10;
1901         }
1902
1903         units = 1;
1904         if (end != NULL) {
1905                 switch (*end) {
1906                 case 'p': case 'P':
1907                         units <<= 10;
1908                 case 't': case 'T':
1909                         units <<= 10;
1910                 case 'g': case 'G':
1911                         units <<= 10;
1912                 case 'm': case 'M':
1913                         units <<= 10;
1914                 case 'k': case 'K':
1915                         units <<= 10;
1916                 }
1917         }
1918         /* Specified units override the multiplier */
1919         if (units > 1)
1920                 mult = mult < 0 ? -units : units;
1921
1922         frac *= mult;
1923         do_div(frac, frac_d);
1924         *val = whole * mult + frac;
1925         return 0;
1926 }
1927 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
1928
1929 static char *lprocfs_strnstr(const char *s1, const char *s2, size_t len)
1930 {
1931         size_t l2;
1932
1933         l2 = strlen(s2);
1934         if (!l2)
1935                 return (char *)s1;
1936         while (len >= l2) {
1937                 len--;
1938                 if (!memcmp(s1, s2, l2))
1939                         return (char *)s1;
1940                 s1++;
1941         }
1942         return NULL;
1943 }
1944
1945 /**
1946  * Find the string \a name in the input \a buffer, and return a pointer to the
1947  * value immediately following \a name, reducing \a count appropriately.
1948  * If \a name is not found the original \a buffer is returned.
1949  */
1950 char *lprocfs_find_named_value(const char *buffer, const char *name,
1951                                 size_t *count)
1952 {
1953         char *val;
1954         size_t buflen = *count;
1955
1956         /* there is no strnstr() in rhel5 and ubuntu kernels */
1957         val = lprocfs_strnstr(buffer, name, buflen);
1958         if (val == NULL)
1959                 return (char *)buffer;
1960
1961         val += strlen(name);                             /* skip prefix */
1962         while (val < buffer + buflen && isspace(*val)) /* skip separator */
1963                 val++;
1964
1965         *count = 0;
1966         while (val < buffer + buflen && isalnum(*val)) {
1967                 ++*count;
1968                 ++val;
1969         }
1970
1971         return val - *count;
1972 }
1973 EXPORT_SYMBOL(lprocfs_find_named_value);
1974
1975 int lprocfs_seq_create(struct proc_dir_entry *parent,
1976                        const char *name,
1977                        mode_t mode,
1978                        const struct file_operations *seq_fops,
1979                        void *data)
1980 {
1981         struct proc_dir_entry *entry;
1982         ENTRY;
1983
1984         /* Disallow secretly (un)writable entries. */
1985         LASSERT((seq_fops->write == NULL) == ((mode & 0222) == 0));
1986
1987         entry = proc_create_data(name, mode, parent, seq_fops, data);
1988
1989         if (entry == NULL)
1990                 RETURN(-ENOMEM);
1991
1992         RETURN(0);
1993 }
1994 EXPORT_SYMBOL(lprocfs_seq_create);
1995
1996 int lprocfs_obd_seq_create(struct obd_device *dev,
1997                            const char *name,
1998                            mode_t mode,
1999                            const struct file_operations *seq_fops,
2000                            void *data)
2001 {
2002         return (lprocfs_seq_create(dev->obd_proc_entry, name,
2003                                    mode, seq_fops, data));
2004 }
2005 EXPORT_SYMBOL(lprocfs_obd_seq_create);
2006
2007 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
2008 {
2009         if (value >= OBD_HIST_MAX)
2010                 value = OBD_HIST_MAX - 1;
2011
2012         spin_lock(&oh->oh_lock);
2013         oh->oh_buckets[value]++;
2014         spin_unlock(&oh->oh_lock);
2015 }
2016 EXPORT_SYMBOL(lprocfs_oh_tally);
2017
2018 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
2019 {
2020         unsigned int val = 0;
2021
2022         if (likely(value != 0))
2023                 val = min(fls(value - 1), OBD_HIST_MAX);
2024
2025         lprocfs_oh_tally(oh, val);
2026 }
2027 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
2028
2029 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
2030 {
2031         unsigned long ret = 0;
2032         int i;
2033
2034         for (i = 0; i < OBD_HIST_MAX; i++)
2035                 ret +=  oh->oh_buckets[i];
2036         return ret;
2037 }
2038 EXPORT_SYMBOL(lprocfs_oh_sum);
2039
2040 void lprocfs_oh_clear(struct obd_histogram *oh)
2041 {
2042         spin_lock(&oh->oh_lock);
2043         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
2044         spin_unlock(&oh->oh_lock);
2045 }
2046 EXPORT_SYMBOL(lprocfs_oh_clear);
2047
2048 int lprocfs_obd_rd_max_pages_per_rpc(char *page, char **start, off_t off,
2049                                      int count, int *eof, void *data)
2050 {
2051         struct obd_device *dev = data;
2052         struct client_obd *cli = &dev->u.cli;
2053         int rc;
2054
2055         client_obd_list_lock(&cli->cl_loi_list_lock);
2056         rc = snprintf(page, count, "%d\n", cli->cl_max_pages_per_rpc);
2057         client_obd_list_unlock(&cli->cl_loi_list_lock);
2058         return rc;
2059 }
2060 EXPORT_SYMBOL(lprocfs_obd_rd_max_pages_per_rpc);
2061
2062 int lprocfs_obd_max_pages_per_rpc_seq_show(struct seq_file *m, void *data)
2063 {
2064         struct obd_device *dev = data;
2065         struct client_obd *cli = &dev->u.cli;
2066         int rc;
2067
2068         client_obd_list_lock(&cli->cl_loi_list_lock);
2069         rc = seq_printf(m, "%d\n", cli->cl_max_pages_per_rpc);
2070         client_obd_list_unlock(&cli->cl_loi_list_lock);
2071         return rc;
2072 }
2073 EXPORT_SYMBOL(lprocfs_obd_max_pages_per_rpc_seq_show);
2074
2075 int lprocfs_wr_root_squash(const char __user *buffer, unsigned long count,
2076                            struct root_squash_info *squash, char *name)
2077 {
2078         int rc;
2079         char kernbuf[64], *tmp, *errmsg;
2080         unsigned long uid, gid;
2081         ENTRY;
2082
2083         if (count >= sizeof(kernbuf)) {
2084                 errmsg = "string too long";
2085                 GOTO(failed_noprint, rc = -EINVAL);
2086         }
2087         if (copy_from_user(kernbuf, buffer, count)) {
2088                 errmsg = "bad address";
2089                 GOTO(failed_noprint, rc = -EFAULT);
2090         }
2091         kernbuf[count] = '\0';
2092
2093         /* look for uid gid separator */
2094         tmp = strchr(kernbuf, ':');
2095         if (tmp == NULL) {
2096                 errmsg = "needs uid:gid format";
2097                 GOTO(failed, rc = -EINVAL);
2098         }
2099         *tmp = '\0';
2100         tmp++;
2101
2102         /* parse uid */
2103         if (kstrtoul(kernbuf, 0, &uid) != 0) {
2104                 errmsg = "bad uid";
2105                 GOTO(failed, rc = -EINVAL);
2106         }
2107
2108         /* parse gid */
2109         if (kstrtoul(tmp, 0, &gid) != 0) {
2110                 errmsg = "bad gid";
2111                 GOTO(failed, rc = -EINVAL);
2112         }
2113
2114         squash->rsi_uid = uid;
2115         squash->rsi_gid = gid;
2116
2117         LCONSOLE_INFO("%s: root_squash is set to %u:%u\n",
2118                       name, squash->rsi_uid, squash->rsi_gid);
2119         RETURN(count);
2120
2121 failed:
2122         if (tmp != NULL) {
2123                 tmp--;
2124                 *tmp = ':';
2125         }
2126         CWARN("%s: failed to set root_squash to \"%s\", %s, rc = %d\n",
2127               name, kernbuf, errmsg, rc);
2128         RETURN(rc);
2129 failed_noprint:
2130         CWARN("%s: failed to set root_squash due to %s, rc = %d\n",
2131               name, errmsg, rc);
2132         RETURN(rc);
2133 }
2134 EXPORT_SYMBOL(lprocfs_wr_root_squash);
2135
2136
2137 int lprocfs_wr_nosquash_nids(const char __user *buffer, unsigned long count,
2138                              struct root_squash_info *squash, char *name)
2139 {
2140         int rc;
2141         char *kernbuf = NULL;
2142         char *errmsg;
2143         struct list_head tmp;
2144         ENTRY;
2145
2146         if (count > 4096) {
2147                 errmsg = "string too long";
2148                 GOTO(failed, rc = -EINVAL);
2149         }
2150
2151         OBD_ALLOC(kernbuf, count + 1);
2152         if (kernbuf == NULL) {
2153                 errmsg = "no memory";
2154                 GOTO(failed, rc = -ENOMEM);
2155         }
2156         if (copy_from_user(kernbuf, buffer, count)) {
2157                 errmsg = "bad address";
2158                 GOTO(failed, rc = -EFAULT);
2159         }
2160         kernbuf[count] = '\0';
2161
2162         if (count > 0 && kernbuf[count - 1] == '\n')
2163                 kernbuf[count - 1] = '\0';
2164
2165         if (strcmp(kernbuf, "NONE") == 0 || strcmp(kernbuf, "clear") == 0) {
2166                 /* empty string is special case */
2167                 down_write(&squash->rsi_sem);
2168                 if (!list_empty(&squash->rsi_nosquash_nids))
2169                         cfs_free_nidlist(&squash->rsi_nosquash_nids);
2170                 up_write(&squash->rsi_sem);
2171                 LCONSOLE_INFO("%s: nosquash_nids is cleared\n", name);
2172                 OBD_FREE(kernbuf, count + 1);
2173                 RETURN(count);
2174         }
2175
2176         INIT_LIST_HEAD(&tmp);
2177         if (cfs_parse_nidlist(kernbuf, count, &tmp) <= 0) {
2178                 errmsg = "can't parse";
2179                 GOTO(failed, rc = -EINVAL);
2180         }
2181         LCONSOLE_INFO("%s: nosquash_nids set to %s\n",
2182                       name, kernbuf);
2183         OBD_FREE(kernbuf, count + 1);
2184         kernbuf = NULL;
2185
2186         down_write(&squash->rsi_sem);
2187         if (!list_empty(&squash->rsi_nosquash_nids))
2188                 cfs_free_nidlist(&squash->rsi_nosquash_nids);
2189         list_splice(&tmp, &squash->rsi_nosquash_nids);
2190         up_write(&squash->rsi_sem);
2191
2192         RETURN(count);
2193
2194 failed:
2195         if (kernbuf) {
2196                 CWARN("%s: failed to set nosquash_nids to \"%s\", %s rc = %d\n",
2197                       name, kernbuf, errmsg, rc);
2198                 OBD_FREE(kernbuf, count + 1);
2199         } else {
2200                 CWARN("%s: failed to set nosquash_nids due to %s rc = %d\n",
2201                       name, errmsg, rc);
2202         }
2203         RETURN(rc);
2204 }
2205 EXPORT_SYMBOL(lprocfs_wr_nosquash_nids);
2206
2207 #endif /* LPROCFS*/