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