Whamcloud - gitweb
173ad8542b0af247af9c44fc04fb559bcc3026c7
[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, 2012, 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 #ifndef __KERNEL__
44 # include <liblustre.h>
45 #endif
46
47 #include <obd_class.h>
48 #include <lprocfs_status.h>
49 #include <lustre_fsfilt.h>
50 #include <lustre_log.h>
51 #include <lustre_disk.h>
52 #include <lustre/lustre_idl.h>
53 #include <dt_object.h>
54
55 #if defined(LPROCFS)
56
57 static int lprocfs_no_percpu_stats = 0;
58 CFS_MODULE_PARM(lprocfs_no_percpu_stats, "i", int, 0644,
59                 "Do not alloc percpu data for lprocfs stats");
60
61 #define MAX_STRING_SIZE 128
62
63 /* for bug 10866, global variable */
64 DECLARE_RWSEM(_lprocfs_lock);
65 EXPORT_SYMBOL(_lprocfs_lock);
66
67 int lprocfs_single_release(struct inode *inode, struct file *file)
68 {
69         LPROCFS_EXIT();
70         return single_release(inode, file);
71 }
72 EXPORT_SYMBOL(lprocfs_single_release);
73
74 int lprocfs_seq_release(struct inode *inode, struct file *file)
75 {
76         LPROCFS_EXIT();
77         return seq_release(inode, file);
78 }
79 EXPORT_SYMBOL(lprocfs_seq_release);
80
81 static struct proc_dir_entry *__lprocfs_srch(struct proc_dir_entry *head,
82                                              const char *name)
83 {
84         struct proc_dir_entry *temp;
85
86         if (head == NULL)
87                 return NULL;
88
89         temp = head->subdir;
90         while (temp != NULL) {
91                 if (strcmp(temp->name, name) == 0) {
92                         return temp;
93                 }
94
95                 temp = temp->next;
96         }
97         return NULL;
98 }
99
100 struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
101                                     const char *name)
102 {
103         struct proc_dir_entry *temp;
104
105         LPROCFS_SRCH_ENTRY();
106         temp = __lprocfs_srch(head, name);
107         LPROCFS_SRCH_EXIT();
108         return temp;
109 }
110 EXPORT_SYMBOL(lprocfs_srch);
111
112 /* lprocfs API calls */
113
114 /* Function that emulates snprintf but also has the side effect of advancing
115    the page pointer for the next write into the buffer, incrementing the total
116    length written to the buffer, and decrementing the size left in the
117    buffer. */
118 static int lprocfs_obd_snprintf(char **page, int end, int *len,
119                                 const char *format, ...)
120 {
121         va_list list;
122         int n;
123
124         if (*len >= end)
125                 return 0;
126
127         va_start(list, format);
128         n = vsnprintf(*page, end - *len, format, list);
129         va_end(list);
130
131         *page += n; *len += n;
132         return n;
133 }
134
135 cfs_proc_dir_entry_t *lprocfs_add_simple(struct proc_dir_entry *root,
136                                          char *name,
137                                          read_proc_t *read_proc,
138                                          write_proc_t *write_proc,
139                                          void *data,
140                                          struct file_operations *fops)
141 {
142         cfs_proc_dir_entry_t *proc;
143         mode_t mode = 0;
144
145         if (root == NULL || name == NULL)
146                 return ERR_PTR(-EINVAL);
147         if (read_proc)
148                 mode = 0444;
149         if (write_proc)
150                 mode |= 0200;
151         if (fops)
152                 mode = 0644;
153         LPROCFS_WRITE_ENTRY();
154         proc = create_proc_entry(name, mode, root);
155         if (!proc) {
156                 CERROR("LprocFS: No memory to create /proc entry %s", name);
157                 LPROCFS_WRITE_EXIT();
158                 return ERR_PTR(-ENOMEM);
159         }
160         proc->read_proc = read_proc;
161         proc->write_proc = write_proc;
162         proc->data = data;
163         if (fops)
164                 proc->proc_fops = fops;
165         LPROCFS_WRITE_EXIT();
166         return proc;
167 }
168 EXPORT_SYMBOL(lprocfs_add_simple);
169
170 struct proc_dir_entry *lprocfs_add_symlink(const char *name,
171                         struct proc_dir_entry *parent, const char *format, ...)
172 {
173         struct proc_dir_entry *entry;
174         char *dest;
175         va_list ap;
176
177         if (parent == NULL || format == NULL)
178                 return NULL;
179
180         OBD_ALLOC_WAIT(dest, MAX_STRING_SIZE + 1);
181         if (dest == NULL)
182                 return NULL;
183
184         va_start(ap, format);
185         vsnprintf(dest, MAX_STRING_SIZE, format, ap);
186         va_end(ap);
187
188         entry = proc_symlink(name, parent, dest);
189         if (entry == NULL)
190                 CERROR("LprocFS: Could not create symbolic link from %s to %s",
191                         name, dest);
192
193         OBD_FREE(dest, MAX_STRING_SIZE + 1);
194         return entry;
195 }
196 EXPORT_SYMBOL(lprocfs_add_symlink);
197
198 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
199                                  size_t size, loff_t *ppos)
200 {
201         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
202         char *page, *start = NULL;
203         int rc = 0, eof = 1, count;
204
205         if (*ppos >= CFS_PAGE_SIZE)
206                 return 0;
207
208         page = (char *)__get_free_page(GFP_KERNEL);
209         if (page == NULL)
210                 return -ENOMEM;
211
212         if (LPROCFS_ENTRY_AND_CHECK(dp)) {
213                 rc = -ENOENT;
214                 goto out;
215         }
216
217         OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
218         if (dp->read_proc)
219                 rc = dp->read_proc(page, &start, *ppos, CFS_PAGE_SIZE,
220                                    &eof, dp->data);
221         LPROCFS_EXIT();
222         if (rc <= 0)
223                 goto out;
224
225         /* for lustre proc read, the read count must be less than PAGE_SIZE */
226         LASSERT(eof == 1);
227
228         if (start == NULL) {
229                 rc -= *ppos;
230                 if (rc < 0)
231                         rc = 0;
232                 if (rc == 0)
233                         goto out;
234                 start = page + *ppos;
235         } else if (start < page) {
236                 start = page;
237         }
238
239         count = (rc < size) ? rc : size;
240         if (cfs_copy_to_user(buf, start, count)) {
241                 rc = -EFAULT;
242                 goto out;
243         }
244         *ppos += count;
245
246 out:
247         free_page((unsigned long)page);
248         return rc;
249 }
250
251 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf,
252                                   size_t size, loff_t *ppos)
253 {
254         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
255         int rc = -EIO;
256
257         if (LPROCFS_ENTRY_AND_CHECK(dp))
258                 return -ENOENT;
259         if (dp->write_proc)
260                 rc = dp->write_proc(f, buf, size, dp->data);
261         LPROCFS_EXIT();
262         return rc;
263 }
264
265 static struct file_operations lprocfs_generic_fops = {
266         .owner = THIS_MODULE,
267         .read = lprocfs_fops_read,
268         .write = lprocfs_fops_write,
269 };
270
271 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
272 {
273         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
274         struct obd_device *obd = dp->data;
275
276         cfs_atomic_inc(&obd->obd_evict_inprogress);
277
278         return 0;
279 }
280
281 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
282 {
283         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
284         struct obd_device *obd = dp->data;
285
286         cfs_atomic_dec(&obd->obd_evict_inprogress);
287         cfs_waitq_signal(&obd->obd_evict_inprogress_waitq);
288
289         return 0;
290 }
291
292 struct file_operations lprocfs_evict_client_fops = {
293         .owner = THIS_MODULE,
294         .read = lprocfs_fops_read,
295         .write = lprocfs_fops_write,
296         .open = lprocfs_evict_client_open,
297         .release = lprocfs_evict_client_release,
298 };
299 EXPORT_SYMBOL(lprocfs_evict_client_fops);
300
301 /**
302  * Add /proc entries.
303  *
304  * \param root [in]  The parent proc entry on which new entry will be added.
305  * \param list [in]  Array of proc entries to be added.
306  * \param data [in]  The argument to be passed when entries read/write routines
307  *                   are called through /proc file.
308  *
309  * \retval 0   on success
310  *         < 0 on error
311  */
312 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
313                      void *data)
314 {
315         int rc = 0;
316
317         if (root == NULL || list == NULL)
318                 return -EINVAL;
319
320         LPROCFS_WRITE_ENTRY();
321         while (list->name != NULL) {
322                 struct proc_dir_entry *cur_root, *proc;
323                 char *pathcopy, *cur, *next, pathbuf[64];
324                 int pathsize = strlen(list->name) + 1;
325
326                 proc = NULL;
327                 cur_root = root;
328
329                 /* need copy of path for strsep */
330                 if (strlen(list->name) > sizeof(pathbuf) - 1) {
331                         OBD_ALLOC(pathcopy, pathsize);
332                         if (pathcopy == NULL)
333                                 GOTO(out, rc = -ENOMEM);
334                 } else {
335                         pathcopy = pathbuf;
336                 }
337
338                 next = pathcopy;
339                 strcpy(pathcopy, list->name);
340
341                 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
342                         if (*cur =='\0') /* skip double/trailing "/" */
343                                 continue;
344
345                         proc = __lprocfs_srch(cur_root, cur);
346                         CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
347                                cur_root->name, cur, next,
348                                (proc ? "exists" : "new"));
349                         if (next != NULL) {
350                                 cur_root = (proc ? proc :
351                                             proc_mkdir(cur, cur_root));
352                         } else if (proc == NULL) {
353                                 mode_t mode = 0;
354                                 if (list->proc_mode != 0000) {
355                                         mode = list->proc_mode;
356                                 } else {
357                                         if (list->read_fptr)
358                                                 mode = 0444;
359                                         if (list->write_fptr)
360                                                 mode |= 0200;
361                                 }
362                                 proc = create_proc_entry(cur, mode, cur_root);
363                         }
364                 }
365
366                 if (pathcopy != pathbuf)
367                         OBD_FREE(pathcopy, pathsize);
368
369                 if (cur_root == NULL || proc == NULL) {
370                         CERROR("LprocFS: No memory to create /proc entry %s",
371                                list->name);
372                         GOTO(out, rc = -ENOMEM);
373                 }
374
375                 if (list->fops)
376                         proc->proc_fops = list->fops;
377                 else
378                         proc->proc_fops = &lprocfs_generic_fops;
379                 proc->read_proc = list->read_fptr;
380                 proc->write_proc = list->write_fptr;
381                 proc->data = (list->data ? list->data : data);
382                 list++;
383         }
384 out:
385         LPROCFS_WRITE_EXIT();
386         return rc;
387 }
388 EXPORT_SYMBOL(lprocfs_add_vars);
389
390 void lprocfs_remove_nolock(struct proc_dir_entry **rooth)
391 {
392         struct proc_dir_entry *root = *rooth;
393         struct proc_dir_entry *temp = root;
394         struct proc_dir_entry *rm_entry;
395         struct proc_dir_entry *parent;
396
397         if (!root)
398                 return;
399         *rooth = NULL;
400
401         parent = root->parent;
402         LASSERT(parent != NULL);
403
404         while (1) {
405                 while (temp->subdir != NULL)
406                         temp = temp->subdir;
407
408                 rm_entry = temp;
409                 temp = temp->parent;
410
411                 /* Memory corruption once caused this to fail, and
412                    without this LASSERT we would loop here forever. */
413                 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
414                          "0x%p  %s/%s len %d\n", rm_entry, temp->name,
415                          rm_entry->name, (int)strlen(rm_entry->name));
416
417                 remove_proc_entry(rm_entry->name, temp);
418                 if (temp == parent)
419                         break;
420         }
421 }
422
423 void lprocfs_remove(struct proc_dir_entry **rooth)
424 {
425         LPROCFS_WRITE_ENTRY(); /* search vs remove race */
426         lprocfs_remove_nolock(rooth);
427         LPROCFS_WRITE_EXIT();
428 }
429 EXPORT_SYMBOL(lprocfs_remove);
430
431 void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
432 {
433         LASSERT(parent != NULL);
434         remove_proc_entry(name, parent);
435 }
436 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
437
438 void lprocfs_try_remove_proc_entry(const char *name,
439                                    struct proc_dir_entry *parent)
440 {
441         struct proc_dir_entry    *t = NULL;
442         struct proc_dir_entry   **p;
443         int                       len, busy = 0;
444
445         LASSERT(parent != NULL);
446         len = strlen(name);
447
448         LPROCFS_WRITE_ENTRY();
449
450         /* lookup target name */
451         for (p = &parent->subdir; *p; p = &(*p)->next) {
452                 if ((*p)->namelen != len)
453                         continue;
454                 if (memcmp(name, (*p)->name, len))
455                         continue;
456                 t = *p;
457                 break;
458         }
459
460         if (t) {
461                 /* verify it's empty: do not count "num_refs" */
462                 for (p = &t->subdir; *p; p = &(*p)->next) {
463                         if ((*p)->namelen != strlen("num_refs")) {
464                                 busy = 1;
465                                 break;
466                         }
467                         if (memcmp("num_refs", (*p)->name,
468                                    strlen("num_refs"))) {
469                                 busy = 1;
470                                 break;
471                         }
472                 }
473         }
474
475         if (busy == 0)
476                 lprocfs_remove_nolock(&t);
477
478         LPROCFS_WRITE_EXIT();
479
480         return;
481 }
482 EXPORT_SYMBOL(lprocfs_try_remove_proc_entry);
483
484 struct proc_dir_entry *lprocfs_register(const char *name,
485                                         struct proc_dir_entry *parent,
486                                         struct lprocfs_vars *list, void *data)
487 {
488         struct proc_dir_entry *newchild;
489
490         newchild = lprocfs_srch(parent, name);
491         if (newchild != NULL) {
492                 CERROR(" Lproc: Attempting to register %s more than once \n",
493                        name);
494                 return ERR_PTR(-EALREADY);
495         }
496
497         newchild = proc_mkdir(name, parent);
498         if (newchild != NULL && list != NULL) {
499                 int rc = lprocfs_add_vars(newchild, list, data);
500                 if (rc) {
501                         lprocfs_remove(&newchild);
502                         return ERR_PTR(rc);
503                 }
504         }
505         return newchild;
506 }
507 EXPORT_SYMBOL(lprocfs_register);
508
509 /* Generic callbacks */
510 int lprocfs_rd_uint(char *page, char **start, off_t off,
511                     int count, int *eof, void *data)
512 {
513         unsigned int *temp = data;
514         return snprintf(page, count, "%u\n", *temp);
515 }
516 EXPORT_SYMBOL(lprocfs_rd_uint);
517
518 int lprocfs_wr_uint(struct file *file, const char *buffer,
519                     unsigned long count, void *data)
520 {
521         unsigned *p = data;
522         char dummy[MAX_STRING_SIZE + 1], *end;
523         unsigned long tmp;
524
525         dummy[MAX_STRING_SIZE] = '\0';
526         if (cfs_copy_from_user(dummy, buffer, MAX_STRING_SIZE))
527                 return -EFAULT;
528
529         tmp = simple_strtoul(dummy, &end, 0);
530         if (dummy == end)
531                 return -EINVAL;
532
533         *p = (unsigned int)tmp;
534         return count;
535 }
536 EXPORT_SYMBOL(lprocfs_wr_uint);
537
538 int lprocfs_rd_u64(char *page, char **start, off_t off,
539                    int count, int *eof, void *data)
540 {
541         LASSERT(data != NULL);
542         *eof = 1;
543         return snprintf(page, count, LPU64"\n", *(__u64 *)data);
544 }
545 EXPORT_SYMBOL(lprocfs_rd_u64);
546
547 int lprocfs_rd_atomic(char *page, char **start, off_t off,
548                    int count, int *eof, void *data)
549 {
550         cfs_atomic_t *atom = data;
551         LASSERT(atom != NULL);
552         *eof = 1;
553         return snprintf(page, count, "%d\n", cfs_atomic_read(atom));
554 }
555 EXPORT_SYMBOL(lprocfs_rd_atomic);
556
557 int lprocfs_wr_atomic(struct file *file, const char *buffer,
558                       unsigned long count, void *data)
559 {
560         cfs_atomic_t *atm = data;
561         int val = 0;
562         int rc;
563
564         rc = lprocfs_write_helper(buffer, count, &val);
565         if (rc < 0)
566                 return rc;
567
568         if (val <= 0)
569                 return -ERANGE;
570
571         cfs_atomic_set(atm, val);
572         return count;
573 }
574 EXPORT_SYMBOL(lprocfs_wr_atomic);
575
576 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
577                     int *eof, void *data)
578 {
579         struct obd_device *obd = data;
580
581         LASSERT(obd != NULL);
582         *eof = 1;
583         return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
584 }
585 EXPORT_SYMBOL(lprocfs_rd_uuid);
586
587 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
588                     int *eof, void *data)
589 {
590         struct obd_device *dev = data;
591
592         LASSERT(dev != NULL);
593         LASSERT(dev->obd_name != NULL);
594         *eof = 1;
595         return snprintf(page, count, "%s\n", dev->obd_name);
596 }
597 EXPORT_SYMBOL(lprocfs_rd_name);
598
599 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
600                        int *eof, void *data)
601 {
602         struct obd_device *obd = data;
603         struct obd_statfs  osfs;
604         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
605                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
606                             OBD_STATFS_NODELAY);
607         if (!rc) {
608                 *eof = 1;
609                 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
610         }
611         return rc;
612 }
613 EXPORT_SYMBOL(lprocfs_rd_blksize);
614
615 int lprocfs_osd_rd_blksize(char *page, char **start, off_t off,
616                                 int count, int *eof, void *data)
617 {
618         struct dt_device *dt = data;
619         struct obd_statfs osfs;
620         int rc = dt_statfs(NULL, dt, &osfs);
621         if (!rc) {
622                 *eof = 1;
623                 rc = snprintf(page, count, "%d\n",
624                                 (unsigned) osfs.os_bsize);
625         }
626         return rc;
627 }
628 EXPORT_SYMBOL(lprocfs_osd_rd_blksize);
629
630 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
631                            int *eof, void *data)
632 {
633         struct obd_device *obd = data;
634         struct obd_statfs  osfs;
635         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
636                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
637                             OBD_STATFS_NODELAY);
638         if (!rc) {
639                 __u32 blk_size = osfs.os_bsize >> 10;
640                 __u64 result = osfs.os_blocks;
641
642                 while (blk_size >>= 1)
643                         result <<= 1;
644
645                 *eof = 1;
646                 rc = snprintf(page, count, LPU64"\n", result);
647         }
648         return rc;
649 }
650 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
651
652 int lprocfs_osd_rd_kbytestotal(char *page, char **start, off_t off,
653                                 int count, int *eof, void *data)
654 {
655         struct dt_device *dt = data;
656         struct obd_statfs osfs;
657         int rc = dt_statfs(NULL, dt, &osfs);
658         if (!rc) {
659                 __u32 blk_size = osfs.os_bsize >> 10;
660                 __u64 result = osfs.os_blocks;
661
662                 while (blk_size >>= 1)
663                         result <<= 1;
664
665                 *eof = 1;
666                 rc = snprintf(page, count, LPU64"\n", result);
667         }
668         return rc;
669 }
670 EXPORT_SYMBOL(lprocfs_osd_rd_kbytestotal);
671
672 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
673                           int *eof, void *data)
674 {
675         struct obd_device *obd = data;
676         struct obd_statfs  osfs;
677         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
678                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
679                             OBD_STATFS_NODELAY);
680         if (!rc) {
681                 __u32 blk_size = osfs.os_bsize >> 10;
682                 __u64 result = osfs.os_bfree;
683
684                 while (blk_size >>= 1)
685                         result <<= 1;
686
687                 *eof = 1;
688                 rc = snprintf(page, count, LPU64"\n", result);
689         }
690         return rc;
691 }
692 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
693
694 int lprocfs_osd_rd_kbytesfree(char *page, char **start, off_t off,
695                                 int count, int *eof, void *data)
696 {
697         struct dt_device *dt = data;
698         struct obd_statfs osfs;
699         int rc = dt_statfs(NULL, dt, &osfs);
700         if (!rc) {
701                 __u32 blk_size = osfs.os_bsize >> 10;
702                 __u64 result = osfs.os_bfree;
703
704                 while (blk_size >>= 1)
705                         result <<= 1;
706
707                 *eof = 1;
708                 rc = snprintf(page, count, LPU64"\n", result);
709         }
710         return rc;
711 }
712 EXPORT_SYMBOL(lprocfs_osd_rd_kbytesfree);
713
714 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
715                            int *eof, void *data)
716 {
717         struct obd_device *obd = data;
718         struct obd_statfs  osfs;
719         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
720                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
721                             OBD_STATFS_NODELAY);
722         if (!rc) {
723                 __u32 blk_size = osfs.os_bsize >> 10;
724                 __u64 result = osfs.os_bavail;
725
726                 while (blk_size >>= 1)
727                         result <<= 1;
728
729                 *eof = 1;
730                 rc = snprintf(page, count, LPU64"\n", result);
731         }
732         return rc;
733 }
734 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
735
736 int lprocfs_osd_rd_kbytesavail(char *page, char **start, off_t off,
737                                 int count, int *eof, void *data)
738 {
739         struct dt_device *dt = data;
740         struct obd_statfs osfs;
741         int rc = dt_statfs(NULL, dt, &osfs);
742         if (!rc) {
743                 __u32 blk_size = osfs.os_bsize >> 10;
744                 __u64 result = osfs.os_bavail;
745
746                 while (blk_size >>= 1)
747                         result <<= 1;
748
749                 *eof = 1;
750                 rc = snprintf(page, count, LPU64"\n", result);
751         }
752         return rc;
753 }
754 EXPORT_SYMBOL(lprocfs_osd_rd_kbytesavail);
755
756 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
757                           int *eof, void *data)
758 {
759         struct obd_device *obd = data;
760         struct obd_statfs  osfs;
761         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
762                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
763                             OBD_STATFS_NODELAY);
764         if (!rc) {
765                 *eof = 1;
766                 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
767         }
768
769         return rc;
770 }
771 EXPORT_SYMBOL(lprocfs_rd_filestotal);
772
773 int lprocfs_osd_rd_filestotal(char *page, char **start, off_t off,
774                                 int count, int *eof, void *data)
775 {
776         struct dt_device *dt = data;
777         struct obd_statfs osfs;
778         int rc = dt_statfs(NULL, dt, &osfs);
779         if (!rc) {
780                 *eof = 1;
781                 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
782         }
783
784         return rc;
785 }
786 EXPORT_SYMBOL(lprocfs_osd_rd_filestotal);
787
788 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
789                          int *eof, void *data)
790 {
791         struct obd_device *obd = data;
792         struct obd_statfs  osfs;
793         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
794                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
795                             OBD_STATFS_NODELAY);
796         if (!rc) {
797                 *eof = 1;
798                 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
799         }
800         return rc;
801 }
802 EXPORT_SYMBOL(lprocfs_rd_filesfree);
803
804 int lprocfs_osd_rd_filesfree(char *page, char **start, off_t off,
805                                 int count, int *eof, void *data)
806 {
807         struct dt_device *dt = data;
808         struct obd_statfs osfs;
809         int rc = dt_statfs(NULL, dt, &osfs);
810         if (!rc) {
811                 *eof = 1;
812                 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
813         }
814         return rc;
815 }
816 EXPORT_SYMBOL(lprocfs_osd_rd_filesfree);
817
818 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
819                            int *eof, void *data)
820 {
821         struct obd_device *obd = data;
822         struct obd_import *imp;
823         char *imp_state_name = NULL;
824         int rc = 0;
825
826         LASSERT(obd != NULL);
827         LPROCFS_CLIMP_CHECK(obd);
828         imp = obd->u.cli.cl_import;
829         imp_state_name = ptlrpc_import_state_name(imp->imp_state);
830         *eof = 1;
831         rc = snprintf(page, count, "%s\t%s%s\n",
832                       obd2cli_tgt(obd), imp_state_name,
833                       imp->imp_deactive ? "\tDEACTIVATED" : "");
834
835         LPROCFS_CLIMP_EXIT(obd);
836         return rc;
837 }
838 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
839
840 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
841                          int *eof,  void *data)
842 {
843         struct obd_device *obd = data;
844         struct ptlrpc_connection *conn;
845         int rc = 0;
846
847         LASSERT(obd != NULL);
848
849         LPROCFS_CLIMP_CHECK(obd);
850         conn = obd->u.cli.cl_import->imp_connection;
851         *eof = 1;
852         if (conn && obd->u.cli.cl_import) {
853                 rc = snprintf(page, count, "%s\n",
854                               conn->c_remote_uuid.uuid);
855         } else {
856                 rc = snprintf(page, count, "%s\n", "<none>");
857         }
858
859         LPROCFS_CLIMP_EXIT(obd);
860         return rc;
861 }
862 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
863
864 /** add up per-cpu counters */
865 void lprocfs_stats_collect(struct lprocfs_stats *stats, int idx,
866                            struct lprocfs_counter *cnt)
867 {
868         unsigned int                    num_entry;
869         struct lprocfs_counter          *percpu_cntr;
870         struct lprocfs_counter_header   *cntr_header;
871         int                             i;
872         unsigned long                   flags = 0;
873
874         memset(cnt, 0, sizeof(*cnt));
875
876         if (stats == NULL) {
877                 /* set count to 1 to avoid divide-by-zero errs in callers */
878                 cnt->lc_count = 1;
879                 return;
880         }
881
882         cnt->lc_min = LC_MIN_INIT;
883
884         num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
885
886         for (i = 0; i < num_entry; i++) {
887                 if (stats->ls_percpu[i] == NULL)
888                         continue;
889                 cntr_header = &stats->ls_cnt_header[idx];
890                 percpu_cntr = lprocfs_stats_counter_get(stats, i, idx);
891
892                 cnt->lc_count += percpu_cntr->lc_count;
893                 cnt->lc_sum += percpu_cntr->lc_sum;
894                 if (percpu_cntr->lc_min < cnt->lc_min)
895                         cnt->lc_min = percpu_cntr->lc_min;
896                 if (percpu_cntr->lc_max > cnt->lc_max)
897                         cnt->lc_max = percpu_cntr->lc_max;
898                 cnt->lc_sumsquare += percpu_cntr->lc_sumsquare;
899         }
900
901         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
902 }
903 EXPORT_SYMBOL(lprocfs_stats_collect);
904
905 /**
906  * Append a space separated list of current set flags to str.
907  */
908 #define flag2str(flag) \
909         if (imp->imp_##flag && max - len > 0) \
910              len += snprintf(str + len, max - len, "%s" #flag, len ? ", " : "");
911 static int obd_import_flags2str(struct obd_import *imp, char *str, int max)
912 {
913         int len = 0;
914
915         if (imp->imp_obd->obd_no_recov)
916                 len += snprintf(str, max - len, "no_recov");
917
918         flag2str(invalid);
919         flag2str(deactive);
920         flag2str(replayable);
921         flag2str(pingable);
922         return len;
923 }
924 #undef flags2str
925
926 static const char *obd_connect_names[] = {
927         "read_only",
928         "lov_index",
929         "unused",
930         "write_grant",
931         "server_lock",
932         "version",
933         "request_portal",
934         "acl",
935         "xattr",
936         "create_on_write",
937         "truncate_lock",
938         "initial_transno",
939         "inode_bit_locks",
940         "join_file(obsolete)",
941         "getattr_by_fid",
942         "no_oh_for_devices",
943         "remote_client",
944         "remote_client_by_force",
945         "max_byte_per_rpc",
946         "64bit_qdata",
947         "mds_capability",
948         "oss_capability",
949         "early_lock_cancel",
950         "som",
951         "adaptive_timeouts",
952         "lru_resize",
953         "mds_mds_connection",
954         "real_conn",
955         "change_qunit_size",
956         "alt_checksum_algorithm",
957         "fid_is_enabled",
958         "version_recovery",
959         "pools",
960         "grant_shrink",
961         "skip_orphan",
962         "large_ea",
963         "full20",
964         "layout_lock",
965         "64bithash",
966         "object_max_bytes",
967         "imp_recov",
968         "jobstats",
969         "umask",
970         "einprogress",
971         "grant_param",
972         "flock_owner",
973         "lvb_type",
974         "nanoseconds_times",
975         "lightweight_conn",
976         "short_io",
977         "pingless",
978         "unknown",
979         NULL
980 };
981
982 int obd_connect_flags2str(char *page, int count, __u64 flags, char *sep)
983 {
984         __u64 mask = 1;
985         int i, ret = 0;
986
987         for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
988                 if (flags & mask)
989                         ret += snprintf(page + ret, count - ret, "%s%s",
990                                         ret ? sep : "", obd_connect_names[i]);
991         }
992         if (flags & ~(mask - 1))
993                 ret += snprintf(page + ret, count - ret,
994                                 "%sunknown flags "LPX64,
995                                 ret ? sep : "", flags & ~(mask - 1));
996         return ret;
997 }
998 EXPORT_SYMBOL(obd_connect_flags2str);
999
1000 int lprocfs_rd_import(char *page, char **start, off_t off, int count,
1001                       int *eof, void *data)
1002 {
1003         struct lprocfs_counter          ret;
1004         struct lprocfs_counter_header   *header;
1005         struct obd_device               *obd    = (struct obd_device *)data;
1006         struct obd_import               *imp;
1007         struct obd_import_conn          *conn;
1008         int                             i;
1009         int                             j;
1010         int                             k;
1011         int                             rw      = 0;
1012
1013         LASSERT(obd != NULL);
1014         LPROCFS_CLIMP_CHECK(obd);
1015         imp = obd->u.cli.cl_import;
1016         *eof = 1;
1017
1018         i = snprintf(page, count,
1019                      "import:\n"
1020                      "    name: %s\n"
1021                      "    target: %s\n"
1022                      "    state: %s\n"
1023                      "    instance: %u\n"
1024                      "    connect_flags: [",
1025                      obd->obd_name,
1026                      obd2cli_tgt(obd),
1027                      ptlrpc_import_state_name(imp->imp_state),
1028                      imp->imp_connect_data.ocd_instance);
1029         i += obd_connect_flags2str(page + i, count - i,
1030                                    imp->imp_connect_data.ocd_connect_flags,
1031                                    ", ");
1032         i += snprintf(page + i, count - i,
1033                       "]\n"
1034                       "    import_flags: [");
1035         i += obd_import_flags2str(imp, page + i, count - i);
1036
1037         i += snprintf(page + i, count - i,
1038                       "]\n"
1039                       "    connection:\n"
1040                       "       failover_nids: [");
1041         spin_lock(&imp->imp_lock);
1042         j = 0;
1043         cfs_list_for_each_entry(conn, &imp->imp_conn_list, oic_item) {
1044                 i += snprintf(page + i, count - i, "%s%s", j ? ", " : "",
1045                               libcfs_nid2str(conn->oic_conn->c_peer.nid));
1046                 j++;
1047         }
1048         i += snprintf(page + i, count - i,
1049                       "]\n"
1050                       "       current_connection: %s\n"
1051                       "       connection_attempts: %u\n"
1052                       "       generation: %u\n"
1053                       "       in-progress_invalidations: %u\n",
1054                       imp->imp_connection == NULL ? "<none>" :
1055                               libcfs_nid2str(imp->imp_connection->c_peer.nid),
1056                       imp->imp_conn_cnt,
1057                       imp->imp_generation,
1058                       cfs_atomic_read(&imp->imp_inval_count));
1059         spin_unlock(&imp->imp_lock);
1060
1061         if (obd->obd_svc_stats == NULL)
1062                 goto out_climp;
1063
1064         header = &obd->obd_svc_stats->ls_cnt_header[PTLRPC_REQWAIT_CNTR];
1065         lprocfs_stats_collect(obd->obd_svc_stats, PTLRPC_REQWAIT_CNTR, &ret);
1066         if (ret.lc_count != 0) {
1067                 /* first argument to do_div MUST be __u64 */
1068                 __u64 sum = ret.lc_sum;
1069                 do_div(sum, ret.lc_count);
1070                 ret.lc_sum = sum;
1071         } else
1072                 ret.lc_sum = 0;
1073         i += snprintf(page + i, count - i,
1074                       "    rpcs:\n"
1075                       "       inflight: %u\n"
1076                       "       unregistering: %u\n"
1077                       "       timeouts: %u\n"
1078                       "       avg_waittime: "LPU64" %s\n",
1079                       cfs_atomic_read(&imp->imp_inflight),
1080                       cfs_atomic_read(&imp->imp_unregistering),
1081                       cfs_atomic_read(&imp->imp_timeouts),
1082                       ret.lc_sum, header->lc_units);
1083
1084         k = 0;
1085         for(j = 0; j < IMP_AT_MAX_PORTALS; j++) {
1086                 if (imp->imp_at.iat_portal[j] == 0)
1087                         break;
1088                 k = max_t(unsigned int, k,
1089                           at_get(&imp->imp_at.iat_service_estimate[j]));
1090         }
1091         i += snprintf(page + i, count - i,
1092                       "    service_estimates:\n"
1093                       "       services: %u sec\n"
1094                       "       network: %u sec\n",
1095                       k,
1096                       at_get(&imp->imp_at.iat_net_latency));
1097
1098         i += snprintf(page + i, count - i,
1099                       "    transactions:\n"
1100                       "       last_replay: "LPU64"\n"
1101                       "       peer_committed: "LPU64"\n"
1102                       "       last_checked: "LPU64"\n",
1103                       imp->imp_last_replay_transno,
1104                       imp->imp_peer_committed_transno,
1105                       imp->imp_last_transno_checked);
1106
1107         /* avg data rates */
1108         for (rw = 0; rw <= 1; rw++) {
1109                 lprocfs_stats_collect(obd->obd_svc_stats,
1110                                       PTLRPC_LAST_CNTR + BRW_READ_BYTES + rw,
1111                                       &ret);
1112                 if (ret.lc_sum > 0 && ret.lc_count > 0) {
1113                         /* first argument to do_div MUST be __u64 */
1114                         __u64 sum = ret.lc_sum;
1115                         do_div(sum, ret.lc_count);
1116                         ret.lc_sum = sum;
1117                         i += snprintf(page + i, count - i,
1118                                       "    %s_data_averages:\n"
1119                                       "       bytes_per_rpc: "LPU64"\n",
1120                                       rw ? "write" : "read",
1121                                       ret.lc_sum);
1122                 }
1123                 k = (int)ret.lc_sum;
1124                 j = opcode_offset(OST_READ + rw) + EXTRA_MAX_OPCODES;
1125                 header = &obd->obd_svc_stats->ls_cnt_header[j];
1126                 lprocfs_stats_collect(obd->obd_svc_stats, j, &ret);
1127                 if (ret.lc_sum > 0 && ret.lc_count != 0) {
1128                         /* first argument to do_div MUST be __u64 */
1129                         __u64 sum = ret.lc_sum;
1130                         do_div(sum, ret.lc_count);
1131                         ret.lc_sum = sum;
1132                         i += snprintf(page + i, count - i,
1133                                       "       %s_per_rpc: "LPU64"\n",
1134                                       header->lc_units, ret.lc_sum);
1135                         j = (int)ret.lc_sum;
1136                         if (j > 0)
1137                                 i += snprintf(page + i, count - i,
1138                                               "       MB_per_sec: %u.%.02u\n",
1139                                               k / j, (100 * k / j) % 100);
1140                 }
1141         }
1142
1143 out_climp:
1144         LPROCFS_CLIMP_EXIT(obd);
1145         return i;
1146 }
1147 EXPORT_SYMBOL(lprocfs_rd_import);
1148
1149 int lprocfs_rd_state(char *page, char **start, off_t off, int count,
1150                       int *eof, void *data)
1151 {
1152         struct obd_device *obd = (struct obd_device *)data;
1153         struct obd_import *imp;
1154         int i, j, k;
1155
1156         LASSERT(obd != NULL);
1157         LPROCFS_CLIMP_CHECK(obd);
1158         imp = obd->u.cli.cl_import;
1159         *eof = 1;
1160
1161         i = snprintf(page, count, "current_state: %s\n",
1162                      ptlrpc_import_state_name(imp->imp_state));
1163         i += snprintf(page + i, count - i,
1164                       "state_history:\n");
1165         k = imp->imp_state_hist_idx;
1166         for (j = 0; j < IMP_STATE_HIST_LEN; j++) {
1167                 struct import_state_hist *ish =
1168                         &imp->imp_state_hist[(k + j) % IMP_STATE_HIST_LEN];
1169                 if (ish->ish_state == 0)
1170                         continue;
1171                 i += snprintf(page + i, count - i, " - ["CFS_TIME_T", %s]\n",
1172                               ish->ish_time,
1173                               ptlrpc_import_state_name(ish->ish_state));
1174         }
1175
1176         LPROCFS_CLIMP_EXIT(obd);
1177         return i;
1178 }
1179 EXPORT_SYMBOL(lprocfs_rd_state);
1180
1181 int lprocfs_at_hist_helper(char *page, int count, int rc,
1182                            struct adaptive_timeout *at)
1183 {
1184         int i;
1185         for (i = 0; i < AT_BINS; i++)
1186                 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
1187         rc += snprintf(page + rc, count - rc, "\n");
1188         return rc;
1189 }
1190 EXPORT_SYMBOL(lprocfs_at_hist_helper);
1191
1192 /* See also ptlrpc_lprocfs_rd_timeouts */
1193 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
1194                         int *eof, void *data)
1195 {
1196         struct obd_device *obd = (struct obd_device *)data;
1197         struct obd_import *imp;
1198         unsigned int cur, worst;
1199         time_t now, worstt;
1200         struct dhms ts;
1201         int i, rc = 0;
1202
1203         LASSERT(obd != NULL);
1204         LPROCFS_CLIMP_CHECK(obd);
1205         imp = obd->u.cli.cl_import;
1206         *eof = 1;
1207
1208         now = cfs_time_current_sec();
1209
1210         /* Some network health info for kicks */
1211         s2dhms(&ts, now - imp->imp_last_reply_time);
1212         rc += snprintf(page + rc, count - rc,
1213                        "%-10s : %ld, "DHMS_FMT" ago\n",
1214                        "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
1215
1216         cur = at_get(&imp->imp_at.iat_net_latency);
1217         worst = imp->imp_at.iat_net_latency.at_worst_ever;
1218         worstt = imp->imp_at.iat_net_latency.at_worst_time;
1219         s2dhms(&ts, now - worstt);
1220         rc += snprintf(page + rc, count - rc,
1221                        "%-10s : cur %3u  worst %3u (at %ld, "DHMS_FMT" ago) ",
1222                        "network", cur, worst, worstt, DHMS_VARS(&ts));
1223         rc = lprocfs_at_hist_helper(page, count, rc,
1224                                     &imp->imp_at.iat_net_latency);
1225
1226         for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
1227                 if (imp->imp_at.iat_portal[i] == 0)
1228                         break;
1229                 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
1230                 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
1231                 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
1232                 s2dhms(&ts, now - worstt);
1233                 rc += snprintf(page + rc, count - rc,
1234                                "portal %-2d  : cur %3u  worst %3u (at %ld, "
1235                                DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
1236                                cur, worst, worstt, DHMS_VARS(&ts));
1237                 rc = lprocfs_at_hist_helper(page, count, rc,
1238                                           &imp->imp_at.iat_service_estimate[i]);
1239         }
1240
1241         LPROCFS_CLIMP_EXIT(obd);
1242         return rc;
1243 }
1244 EXPORT_SYMBOL(lprocfs_rd_timeouts);
1245
1246 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
1247                              int count, int *eof, void *data)
1248 {
1249         struct obd_device *obd = data;
1250         __u64 flags;
1251         int ret = 0;
1252
1253         LPROCFS_CLIMP_CHECK(obd);
1254         flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
1255         ret = snprintf(page, count, "flags="LPX64"\n", flags);
1256         ret += obd_connect_flags2str(page + ret, count - ret, flags, "\n");
1257         ret += snprintf(page + ret, count - ret, "\n");
1258         LPROCFS_CLIMP_EXIT(obd);
1259         return ret;
1260 }
1261 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
1262
1263 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
1264                            int *eof,  void *data)
1265 {
1266         struct obd_device *obd = data;
1267
1268         LASSERT(obd != NULL);
1269         *eof = 1;
1270         return snprintf(page, count, "%u\n", obd->obd_num_exports);
1271 }
1272 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1273
1274 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
1275                        int *eof, void *data)
1276 {
1277         struct obd_type *class = (struct obd_type*) data;
1278
1279         LASSERT(class != NULL);
1280         *eof = 1;
1281         return snprintf(page, count, "%d\n", class->typ_refcnt);
1282 }
1283 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1284
1285 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
1286 {
1287         int rc = 0;
1288
1289         LASSERT(obd != NULL);
1290         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
1291         LASSERT(obd->obd_type->typ_procroot != NULL);
1292
1293         obd->obd_proc_entry = lprocfs_register(obd->obd_name,
1294                                                obd->obd_type->typ_procroot,
1295                                                list, obd);
1296         if (IS_ERR(obd->obd_proc_entry)) {
1297                 rc = PTR_ERR(obd->obd_proc_entry);
1298                 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
1299                 obd->obd_proc_entry = NULL;
1300         }
1301         return rc;
1302 }
1303 EXPORT_SYMBOL(lprocfs_obd_setup);
1304
1305 int lprocfs_obd_cleanup(struct obd_device *obd)
1306 {
1307         if (!obd)
1308                 return -EINVAL;
1309         if (obd->obd_proc_exports_entry) {
1310                 /* Should be no exports left */
1311                 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
1312                 lprocfs_remove(&obd->obd_proc_exports_entry);
1313                 obd->obd_proc_exports_entry = NULL;
1314         }
1315         if (obd->obd_proc_entry) {
1316                 lprocfs_remove(&obd->obd_proc_entry);
1317                 obd->obd_proc_entry = NULL;
1318         }
1319         return 0;
1320 }
1321 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1322
1323 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
1324 {
1325         CDEBUG(D_CONFIG, "stat %p - data %p/%p\n", client_stat,
1326                client_stat->nid_proc, client_stat->nid_stats);
1327
1328         LASSERTF(cfs_atomic_read(&client_stat->nid_exp_ref_count) == 0,
1329                  "nid %s:count %d\n", libcfs_nid2str(client_stat->nid),
1330                  atomic_read(&client_stat->nid_exp_ref_count));
1331
1332         if (client_stat->nid_proc)
1333                 lprocfs_remove(&client_stat->nid_proc);
1334
1335         if (client_stat->nid_stats)
1336                 lprocfs_free_stats(&client_stat->nid_stats);
1337
1338         if (client_stat->nid_ldlm_stats)
1339                 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
1340
1341         OBD_FREE_PTR(client_stat);
1342         return;
1343
1344 }
1345
1346 void lprocfs_free_per_client_stats(struct obd_device *obd)
1347 {
1348         cfs_hash_t *hash = obd->obd_nid_stats_hash;
1349         struct nid_stat *stat;
1350         ENTRY;
1351
1352         /* we need extra list - because hash_exit called to early */
1353         /* not need locking because all clients is died */
1354         while (!cfs_list_empty(&obd->obd_nid_stats)) {
1355                 stat = cfs_list_entry(obd->obd_nid_stats.next,
1356                                       struct nid_stat, nid_list);
1357                 cfs_list_del_init(&stat->nid_list);
1358                 cfs_hash_del(hash, &stat->nid, &stat->nid_hash);
1359                 lprocfs_free_client_stats(stat);
1360         }
1361         EXIT;
1362 }
1363 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
1364
1365 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
1366                                           enum lprocfs_stats_flags flags)
1367 {
1368         struct lprocfs_stats    *stats;
1369         unsigned int            num_entry;
1370         unsigned int            percpusize = 0;
1371         int                     i;
1372
1373         if (num == 0)
1374                 return NULL;
1375
1376         if (lprocfs_no_percpu_stats != 0)
1377                 flags |= LPROCFS_STATS_FLAG_NOPERCPU;
1378
1379         if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
1380                 num_entry = 1;
1381         else
1382                 num_entry = cfs_num_possible_cpus();
1383
1384         /* alloc percpu pointers for all possible cpu slots */
1385         LIBCFS_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_entry]));
1386         if (stats == NULL)
1387                 return NULL;
1388
1389         stats->ls_num = num;
1390         stats->ls_flags = flags;
1391         spin_lock_init(&stats->ls_lock);
1392
1393         /* alloc num of counter headers */
1394         LIBCFS_ALLOC(stats->ls_cnt_header,
1395                      stats->ls_num * sizeof(struct lprocfs_counter_header));
1396         if (stats->ls_cnt_header == NULL)
1397                 goto fail;
1398
1399         if ((flags & LPROCFS_STATS_FLAG_NOPERCPU) != 0) {
1400                 /* contains only one set counters */
1401                 percpusize = lprocfs_stats_counter_size(stats);
1402                 LIBCFS_ALLOC_ATOMIC(stats->ls_percpu[0], percpusize);
1403                 if (stats->ls_percpu[0] == NULL)
1404                         goto fail;
1405                 stats->ls_biggest_alloc_num = 1;
1406         } else if ((flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0) {
1407                 /* alloc all percpu data, currently only obd_memory use this */
1408                 for (i = 0; i < num_entry; ++i)
1409                         if (lprocfs_stats_alloc_one(stats, i) < 0)
1410                                 goto fail;
1411         }
1412
1413         return stats;
1414
1415 fail:
1416         lprocfs_free_stats(&stats);
1417         return NULL;
1418 }
1419 EXPORT_SYMBOL(lprocfs_alloc_stats);
1420
1421 void lprocfs_free_stats(struct lprocfs_stats **statsh)
1422 {
1423         struct lprocfs_stats *stats = *statsh;
1424         unsigned int num_entry;
1425         unsigned int percpusize;
1426         unsigned int i;
1427
1428         if (stats == NULL || stats->ls_num == 0)
1429                 return;
1430         *statsh = NULL;
1431
1432         if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1433                 num_entry = 1;
1434         else
1435                 num_entry = cfs_num_possible_cpus();
1436
1437         percpusize = lprocfs_stats_counter_size(stats);
1438         for (i = 0; i < num_entry; i++)
1439                 if (stats->ls_percpu[i] != NULL)
1440                         LIBCFS_FREE(stats->ls_percpu[i], percpusize);
1441         if (stats->ls_cnt_header != NULL)
1442                 LIBCFS_FREE(stats->ls_cnt_header, stats->ls_num *
1443                                         sizeof(struct lprocfs_counter_header));
1444         LIBCFS_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_entry]));
1445 }
1446 EXPORT_SYMBOL(lprocfs_free_stats);
1447
1448 void lprocfs_clear_stats(struct lprocfs_stats *stats)
1449 {
1450         struct lprocfs_counter          *percpu_cntr;
1451         struct lprocfs_counter_header   *header;
1452         int                             i;
1453         int                             j;
1454         unsigned int                    num_entry;
1455         unsigned long                   flags = 0;
1456
1457         num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
1458
1459         for (i = 0; i < num_entry; i++) {
1460                 if (stats->ls_percpu[i] == NULL)
1461                         continue;
1462                 for (j = 0; j < stats->ls_num; j++) {
1463                         header = &stats->ls_cnt_header[j];
1464                         percpu_cntr = lprocfs_stats_counter_get(stats, i, j);
1465                         percpu_cntr->lc_count           = 0;
1466                         percpu_cntr->lc_min             = LC_MIN_INIT;
1467                         percpu_cntr->lc_max             = 0;
1468                         percpu_cntr->lc_sumsquare       = 0;
1469                         percpu_cntr->lc_sum             = 0;
1470                         if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE)
1471                                 percpu_cntr->lc_sum_irq = 0;
1472                 }
1473         }
1474
1475         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
1476 }
1477 EXPORT_SYMBOL(lprocfs_clear_stats);
1478
1479 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
1480                                        size_t len, loff_t *off)
1481 {
1482         struct seq_file *seq = file->private_data;
1483         struct lprocfs_stats *stats = seq->private;
1484
1485         lprocfs_clear_stats(stats);
1486
1487         return len;
1488 }
1489
1490 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
1491 {
1492         struct lprocfs_stats *stats = p->private;
1493         /* return 1st cpu location */
1494         return (*pos >= stats->ls_num) ? NULL :
1495                 lprocfs_stats_counter_get(stats, 0, *pos);
1496 }
1497
1498 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1499 {
1500 }
1501
1502 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1503 {
1504         struct lprocfs_stats *stats = p->private;
1505         ++*pos;
1506         return (*pos >= stats->ls_num) ? NULL :
1507                 lprocfs_stats_counter_get(stats, 0, *pos);
1508 }
1509
1510 /* seq file export of one lprocfs counter */
1511 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1512 {
1513         struct lprocfs_stats            *stats  = p->private;
1514         struct lprocfs_counter          *cntr   = v;
1515         struct lprocfs_counter          ret;
1516         struct lprocfs_counter_header   *header;
1517         int                             entry_size;
1518         int                             idx;
1519         int                             rc      = 0;
1520
1521         if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
1522                 struct timeval now;
1523                 cfs_gettimeofday(&now);
1524                 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1525                                 "snapshot_time", now.tv_sec, now.tv_usec);
1526                 if (rc < 0)
1527                         return rc;
1528         }
1529         entry_size = sizeof(*cntr);
1530         if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE)
1531                 entry_size += sizeof(__s64);
1532         idx = ((void *)cntr - (void *)&(stats->ls_percpu[0])->lp_cntr[0]) /
1533                 entry_size;
1534
1535         header = &stats->ls_cnt_header[idx];
1536         lprocfs_stats_collect(stats, idx, &ret);
1537
1538         if (ret.lc_count == 0)
1539                 goto out;
1540
1541         rc = seq_printf(p, "%-25s "LPD64" samples [%s]", header->lc_name,
1542                         ret.lc_count, header->lc_units);
1543
1544         if (rc < 0)
1545                 goto out;
1546
1547         if ((header->lc_config & LPROCFS_CNTR_AVGMINMAX) &&
1548             (ret.lc_count > 0)) {
1549                 rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1550                                 ret.lc_min, ret.lc_max, ret.lc_sum);
1551                 if (rc < 0)
1552                         goto out;
1553                 if (header->lc_config & LPROCFS_CNTR_STDDEV)
1554                         rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1555                 if (rc < 0)
1556                         goto out;
1557         }
1558         rc = seq_printf(p, "\n");
1559  out:
1560         return (rc < 0) ? rc : 0;
1561 }
1562
1563 struct seq_operations lprocfs_stats_seq_sops = {
1564         start: lprocfs_stats_seq_start,
1565         stop:  lprocfs_stats_seq_stop,
1566         next:  lprocfs_stats_seq_next,
1567         show:  lprocfs_stats_seq_show,
1568 };
1569
1570 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1571 {
1572         struct proc_dir_entry *dp = PDE(inode);
1573         struct seq_file *seq;
1574         int rc;
1575
1576         if (LPROCFS_ENTRY_AND_CHECK(dp))
1577                 return -ENOENT;
1578
1579         rc = seq_open(file, &lprocfs_stats_seq_sops);
1580         if (rc) {
1581                 LPROCFS_EXIT();
1582                 return rc;
1583         }
1584         seq = file->private_data;
1585         seq->private = dp->data;
1586         return 0;
1587 }
1588
1589 struct file_operations lprocfs_stats_seq_fops = {
1590         .owner   = THIS_MODULE,
1591         .open    = lprocfs_stats_seq_open,
1592         .read    = seq_read,
1593         .write   = lprocfs_stats_seq_write,
1594         .llseek  = seq_lseek,
1595         .release = lprocfs_seq_release,
1596 };
1597
1598 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1599                            struct lprocfs_stats *stats)
1600 {
1601         struct proc_dir_entry *entry;
1602         LASSERT(root != NULL);
1603
1604         LPROCFS_WRITE_ENTRY();
1605         entry = create_proc_entry(name, 0644, root);
1606         if (entry) {
1607                 entry->proc_fops = &lprocfs_stats_seq_fops;
1608                 entry->data = stats;
1609         }
1610
1611         LPROCFS_WRITE_EXIT();
1612
1613         if (entry == NULL)
1614                 return -ENOMEM;
1615
1616         return 0;
1617 }
1618 EXPORT_SYMBOL(lprocfs_register_stats);
1619
1620 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1621                           unsigned conf, const char *name, const char *units)
1622 {
1623         struct lprocfs_counter_header   *header;
1624         struct lprocfs_counter          *percpu_cntr;
1625         unsigned long                   flags = 0;
1626         unsigned int                    i;
1627         unsigned int                    num_cpu;
1628
1629         LASSERT(stats != NULL);
1630
1631         header = &stats->ls_cnt_header[index];
1632         LASSERTF(header != NULL, "Failed to allocate stats header:[%d]%s/%s\n",
1633                  index, name, units);
1634
1635         header->lc_config = conf;
1636         header->lc_name   = name;
1637         header->lc_units  = units;
1638
1639         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
1640         for (i = 0; i < num_cpu; ++i) {
1641                 if (stats->ls_percpu[i] == NULL)
1642                         continue;
1643                 percpu_cntr = lprocfs_stats_counter_get(stats, i, index);
1644                 percpu_cntr->lc_count           = 0;
1645                 percpu_cntr->lc_min             = LC_MIN_INIT;
1646                 percpu_cntr->lc_max             = 0;
1647                 percpu_cntr->lc_sumsquare       = 0;
1648                 percpu_cntr->lc_sum             = 0;
1649                 if ((stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0)
1650                         percpu_cntr->lc_sum_irq = 0;
1651         }
1652         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
1653 }
1654 EXPORT_SYMBOL(lprocfs_counter_init);
1655
1656 #define LPROCFS_OBD_OP_INIT(base, stats, op)                               \
1657 do {                                                                       \
1658         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);              \
1659         LASSERT(coffset < stats->ls_num);                                  \
1660         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");              \
1661 } while (0)
1662
1663 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1664 {
1665         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1666         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1667         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1668         LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1669         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1670         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1671         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1672         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1673         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1674         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1675         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1676         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1677         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1678         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1679         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1680         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1681         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1682         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1683         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1684         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1685         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1686         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1687         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1688         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1689         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1690         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create_async);
1691         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1692         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1693         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1694         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1695         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1696         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1697         LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1698         LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1699         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1700         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1701         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1702         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1703         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1704         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1705         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1706         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1707         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1708         LPROCFS_OBD_OP_INIT(num_private_stats, stats, find_cbdata);
1709         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1710         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1711         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1712         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1713         LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1714         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1715         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1716         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1717         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1718         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1719         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1720         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1721         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1722         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
1723         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1724         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1725         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1726         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1727         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1728         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1729         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1730         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
1731         LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
1732 }
1733 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1734
1735 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1736 {
1737         struct lprocfs_stats *stats;
1738         unsigned int num_stats;
1739         int rc, i;
1740
1741         LASSERT(obd->obd_stats == NULL);
1742         LASSERT(obd->obd_proc_entry != NULL);
1743         LASSERT(obd->obd_cntr_base == 0);
1744
1745         num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1746                 num_private_stats - 1 /* o_owner */;
1747         stats = lprocfs_alloc_stats(num_stats, 0);
1748         if (stats == NULL)
1749                 return -ENOMEM;
1750
1751         lprocfs_init_ops_stats(num_private_stats, stats);
1752
1753         for (i = num_private_stats; i < num_stats; i++) {
1754                 /* If this LBUGs, it is likely that an obd
1755                  * operation was added to struct obd_ops in
1756                  * <obd.h>, and that the corresponding line item
1757                  * LPROCFS_OBD_OP_INIT(.., .., opname)
1758                  * is missing from the list above. */
1759                 LASSERTF(stats->ls_cnt_header[i].lc_name != NULL,
1760                          "Missing obd_stat initializer obd_op "
1761                          "operation at offset %d.\n", i - num_private_stats);
1762         }
1763         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1764         if (rc < 0) {
1765                 lprocfs_free_stats(&stats);
1766         } else {
1767                 obd->obd_stats  = stats;
1768                 obd->obd_cntr_base = num_private_stats;
1769         }
1770         return rc;
1771 }
1772 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1773
1774 void lprocfs_free_obd_stats(struct obd_device *obd)
1775 {
1776         if (obd->obd_stats)
1777                 lprocfs_free_stats(&obd->obd_stats);
1778 }
1779 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1780
1781 #define LPROCFS_MD_OP_INIT(base, stats, op)                             \
1782 do {                                                                    \
1783         unsigned int coffset = base + MD_COUNTER_OFFSET(op);            \
1784         LASSERT(coffset < stats->ls_num);                               \
1785         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
1786 } while (0)
1787
1788 void lprocfs_init_mps_stats(int num_private_stats, struct lprocfs_stats *stats)
1789 {
1790         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1791         LPROCFS_MD_OP_INIT(num_private_stats, stats, null_inode);
1792         LPROCFS_MD_OP_INIT(num_private_stats, stats, find_cbdata);
1793         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1794         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1795         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1796         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1797         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1798         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1799         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1800         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1801         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1802         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1803         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1804         LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1805         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1806         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1807         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1808         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1809         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1810         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1811         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1812         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1813         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1814         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1815         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1816         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1817         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1818         LPROCFS_MD_OP_INIT(num_private_stats, stats, unpack_capa);
1819         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1820         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1821         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1822 }
1823 EXPORT_SYMBOL(lprocfs_init_mps_stats);
1824
1825 int lprocfs_alloc_md_stats(struct obd_device *obd,
1826                            unsigned num_private_stats)
1827 {
1828         struct lprocfs_stats *stats;
1829         unsigned int num_stats;
1830         int rc, i;
1831
1832         LASSERT(obd->md_stats == NULL);
1833         LASSERT(obd->obd_proc_entry != NULL);
1834         LASSERT(obd->md_cntr_base == 0);
1835
1836         num_stats = 1 + MD_COUNTER_OFFSET(revalidate_lock) +
1837                     num_private_stats;
1838         stats = lprocfs_alloc_stats(num_stats, 0);
1839         if (stats == NULL)
1840                 return -ENOMEM;
1841
1842         lprocfs_init_mps_stats(num_private_stats, stats);
1843
1844         for (i = num_private_stats; i < num_stats; i++) {
1845                 if (stats->ls_cnt_header[i].lc_name == NULL) {
1846                         CERROR("Missing md_stat initializer md_op "
1847                                "operation at offset %d. Aborting.\n",
1848                                i - num_private_stats);
1849                         LBUG();
1850                 }
1851         }
1852         rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
1853         if (rc < 0) {
1854                 lprocfs_free_stats(&stats);
1855         } else {
1856                 obd->md_stats  = stats;
1857                 obd->md_cntr_base = num_private_stats;
1858         }
1859         return rc;
1860 }
1861 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
1862
1863 void lprocfs_free_md_stats(struct obd_device *obd)
1864 {
1865         struct lprocfs_stats *stats = obd->md_stats;
1866
1867         if (stats != NULL) {
1868                 obd->md_stats = NULL;
1869                 obd->md_cntr_base = 0;
1870                 lprocfs_free_stats(&stats);
1871         }
1872 }
1873 EXPORT_SYMBOL(lprocfs_free_md_stats);
1874
1875 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1876 {
1877         lprocfs_counter_init(ldlm_stats,
1878                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
1879                              0, "ldlm_enqueue", "reqs");
1880         lprocfs_counter_init(ldlm_stats,
1881                              LDLM_CONVERT - LDLM_FIRST_OPC,
1882                              0, "ldlm_convert", "reqs");
1883         lprocfs_counter_init(ldlm_stats,
1884                              LDLM_CANCEL - LDLM_FIRST_OPC,
1885                              0, "ldlm_cancel", "reqs");
1886         lprocfs_counter_init(ldlm_stats,
1887                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1888                              0, "ldlm_bl_callback", "reqs");
1889         lprocfs_counter_init(ldlm_stats,
1890                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1891                              0, "ldlm_cp_callback", "reqs");
1892         lprocfs_counter_init(ldlm_stats,
1893                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1894                              0, "ldlm_gl_callback", "reqs");
1895 }
1896 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
1897
1898 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1899                          int *eof,  void *data)
1900 {
1901         struct obd_export *exp = data;
1902         LASSERT(exp != NULL);
1903         *eof = 1;
1904         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1905 }
1906
1907 struct exp_uuid_cb_data {
1908         char                   *page;
1909         int                     count;
1910         int                    *eof;
1911         int                    *len;
1912 };
1913
1914 static void
1915 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1916                             int count, int *eof, int *len)
1917 {
1918         cb_data->page = page;
1919         cb_data->count = count;
1920         cb_data->eof = eof;
1921         cb_data->len = len;
1922 }
1923
1924 int lprocfs_exp_print_uuid(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1925                            cfs_hlist_node_t *hnode, void *cb_data)
1926
1927 {
1928         struct obd_export *exp = cfs_hash_object(hs, hnode);
1929         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1930
1931         if (exp->exp_nid_stats)
1932                 *data->len += snprintf((data->page + *data->len),
1933                                        data->count, "%s\n",
1934                                        obd_uuid2str(&exp->exp_client_uuid));
1935         return 0;
1936 }
1937
1938 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1939                         int *eof,  void *data)
1940 {
1941         struct nid_stat *stats = (struct nid_stat *)data;
1942         struct exp_uuid_cb_data cb_data;
1943         struct obd_device *obd = stats->nid_obd;
1944         int len = 0;
1945
1946         *eof = 1;
1947         page[0] = '\0';
1948         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1949         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1950                               lprocfs_exp_print_uuid, &cb_data);
1951         return (*cb_data.len);
1952 }
1953
1954 int lprocfs_exp_print_hash(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1955                            cfs_hlist_node_t *hnode, void *cb_data)
1956
1957 {
1958         struct exp_uuid_cb_data *data = cb_data;
1959         struct obd_export       *exp = cfs_hash_object(hs, hnode);
1960
1961         if (exp->exp_lock_hash != NULL) {
1962                 if (!*data->len) {
1963                         *data->len += cfs_hash_debug_header(data->page,
1964                                                             data->count);
1965                 }
1966                 *data->len += cfs_hash_debug_str(hs, data->page + *data->len,
1967                                                  data->count);
1968         }
1969
1970         return 0;
1971 }
1972
1973 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1974                         int *eof,  void *data)
1975 {
1976         struct nid_stat *stats = (struct nid_stat *)data;
1977         struct exp_uuid_cb_data cb_data;
1978         struct obd_device *obd = stats->nid_obd;
1979         int len = 0;
1980
1981         *eof = 1;
1982         page[0] = '\0';
1983         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1984
1985         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1986                               lprocfs_exp_print_hash, &cb_data);
1987         return (*cb_data.len);
1988 }
1989
1990 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1991                                         int count, int *eof,  void *data)
1992 {
1993         *eof = 1;
1994         return snprintf(page, count, "%s\n",
1995                         "Write into this file to clear all nid stats and "
1996                         "stale nid entries");
1997 }
1998 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1999
2000 static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
2001 {
2002         struct nid_stat *stat = obj;
2003         ENTRY;
2004
2005         CDEBUG(D_INFO,"refcnt %d\n", cfs_atomic_read(&stat->nid_exp_ref_count));
2006         if (cfs_atomic_read(&stat->nid_exp_ref_count) == 1) {
2007                 /* object has only hash references. */
2008                 spin_lock(&stat->nid_obd->obd_nid_lock);
2009                 cfs_list_move(&stat->nid_list, data);
2010                 spin_unlock(&stat->nid_obd->obd_nid_lock);
2011                 RETURN(1);
2012         }
2013         /* we has reference to object - only clear data*/
2014         if (stat->nid_stats)
2015                 lprocfs_clear_stats(stat->nid_stats);
2016
2017         RETURN(0);
2018 }
2019
2020 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
2021                                   unsigned long count, void *data)
2022 {
2023         struct obd_device *obd = (struct obd_device *)data;
2024         struct nid_stat *client_stat;
2025         CFS_LIST_HEAD(free_list);
2026
2027         cfs_hash_cond_del(obd->obd_nid_stats_hash,
2028                           lprocfs_nid_stats_clear_write_cb, &free_list);
2029
2030         while (!cfs_list_empty(&free_list)) {
2031                 client_stat = cfs_list_entry(free_list.next, struct nid_stat,
2032                                              nid_list);
2033                 cfs_list_del_init(&client_stat->nid_list);
2034                 lprocfs_free_client_stats(client_stat);
2035         }
2036
2037         return count;
2038 }
2039 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
2040
2041 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
2042 {
2043         struct nid_stat *new_stat, *old_stat;
2044         struct obd_device *obd = NULL;
2045         cfs_proc_dir_entry_t *entry;
2046         char *buffer = NULL;
2047         int rc = 0;
2048         ENTRY;
2049
2050         *newnid = 0;
2051
2052         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
2053             !exp->exp_obd->obd_nid_stats_hash)
2054                 RETURN(-EINVAL);
2055
2056         /* not test against zero because eric say:
2057          * You may only test nid against another nid, or LNET_NID_ANY.
2058          * Anything else is nonsense.*/
2059         if (!nid || *nid == LNET_NID_ANY)
2060                 RETURN(0);
2061
2062         obd = exp->exp_obd;
2063
2064         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
2065
2066         OBD_ALLOC_PTR(new_stat);
2067         if (new_stat == NULL)
2068                 RETURN(-ENOMEM);
2069
2070         new_stat->nid               = *nid;
2071         new_stat->nid_obd           = exp->exp_obd;
2072         /* we need set default refcount to 1 to balance obd_disconnect */
2073         cfs_atomic_set(&new_stat->nid_exp_ref_count, 1);
2074
2075         old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
2076                                            nid, &new_stat->nid_hash);
2077         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
2078                old_stat, libcfs_nid2str(*nid),
2079                cfs_atomic_read(&new_stat->nid_exp_ref_count));
2080
2081         /* We need to release old stats because lprocfs_exp_cleanup() hasn't
2082          * been and will never be called. */
2083         if (exp->exp_nid_stats) {
2084                 nidstat_putref(exp->exp_nid_stats);
2085                 exp->exp_nid_stats = NULL;
2086         }
2087
2088         /* Return -EALREADY here so that we know that the /proc
2089          * entry already has been created */
2090         if (old_stat != new_stat) {
2091                 exp->exp_nid_stats = old_stat;
2092                 GOTO(destroy_new, rc = -EALREADY);
2093         }
2094         /* not found - create */
2095         OBD_ALLOC(buffer, LNET_NIDSTR_SIZE);
2096         if (buffer == NULL)
2097                 GOTO(destroy_new, rc = -ENOMEM);
2098
2099         memcpy(buffer, libcfs_nid2str(*nid), LNET_NIDSTR_SIZE);
2100         new_stat->nid_proc = lprocfs_register(buffer,
2101                                               obd->obd_proc_exports_entry,
2102                                               NULL, NULL);
2103         OBD_FREE(buffer, LNET_NIDSTR_SIZE);
2104
2105         if (new_stat->nid_proc == NULL) {
2106                 CERROR("Error making export directory for nid %s\n",
2107                        libcfs_nid2str(*nid));
2108                 GOTO(destroy_new_ns, rc = -ENOMEM);
2109         }
2110
2111         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
2112                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
2113         if (IS_ERR(entry)) {
2114                 CWARN("Error adding the NID stats file\n");
2115                 rc = PTR_ERR(entry);
2116                 GOTO(destroy_new_ns, rc);
2117         }
2118
2119         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
2120                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
2121         if (IS_ERR(entry)) {
2122                 CWARN("Error adding the hash file\n");
2123                 rc = PTR_ERR(entry);
2124                 GOTO(destroy_new_ns, rc);
2125         }
2126
2127         exp->exp_nid_stats = new_stat;
2128         *newnid = 1;
2129         /* protect competitive add to list, not need locking on destroy */
2130         spin_lock(&obd->obd_nid_lock);
2131         cfs_list_add(&new_stat->nid_list, &obd->obd_nid_stats);
2132         spin_unlock(&obd->obd_nid_lock);
2133
2134         RETURN(rc);
2135
2136 destroy_new_ns:
2137         if (new_stat->nid_proc != NULL)
2138                 lprocfs_remove(&new_stat->nid_proc);
2139         cfs_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
2140
2141 destroy_new:
2142         nidstat_putref(new_stat);
2143         OBD_FREE_PTR(new_stat);
2144         RETURN(rc);
2145 }
2146 EXPORT_SYMBOL(lprocfs_exp_setup);
2147
2148 int lprocfs_exp_cleanup(struct obd_export *exp)
2149 {
2150         struct nid_stat *stat = exp->exp_nid_stats;
2151
2152         if(!stat || !exp->exp_obd)
2153                 RETURN(0);
2154
2155         nidstat_putref(exp->exp_nid_stats);
2156         exp->exp_nid_stats = NULL;
2157
2158         return 0;
2159 }
2160 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2161
2162 int lprocfs_write_helper(const char *buffer, unsigned long count,
2163                          int *val)
2164 {
2165         return lprocfs_write_frac_helper(buffer, count, val, 1);
2166 }
2167 EXPORT_SYMBOL(lprocfs_write_helper);
2168
2169 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
2170                               int *val, int mult)
2171 {
2172         char kernbuf[20], *end, *pbuf;
2173
2174         if (count > (sizeof(kernbuf) - 1))
2175                 return -EINVAL;
2176
2177         if (cfs_copy_from_user(kernbuf, buffer, count))
2178                 return -EFAULT;
2179
2180         kernbuf[count] = '\0';
2181         pbuf = kernbuf;
2182         if (*pbuf == '-') {
2183                 mult = -mult;
2184                 pbuf++;
2185         }
2186
2187         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2188         if (pbuf == end)
2189                 return -EINVAL;
2190
2191         if (end != NULL && *end == '.') {
2192                 int temp_val, pow = 1;
2193                 int i;
2194
2195                 pbuf = end + 1;
2196                 if (strlen(pbuf) > 5)
2197                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
2198
2199                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2200
2201                 if (pbuf < end) {
2202                         for (i = 0; i < (end - pbuf); i++)
2203                                 pow *= 10;
2204
2205                         *val += temp_val / pow;
2206                 }
2207         }
2208         return 0;
2209 }
2210 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2211
2212 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
2213                              int mult)
2214 {
2215         long decimal_val, frac_val;
2216         int prtn;
2217
2218         if (count < 10)
2219                 return -EINVAL;
2220
2221         decimal_val = val / mult;
2222         prtn = snprintf(buffer, count, "%ld", decimal_val);
2223         frac_val = val % mult;
2224
2225         if (prtn < (count - 4) && frac_val > 0) {
2226                 long temp_frac;
2227                 int i, temp_mult = 1, frac_bits = 0;
2228
2229                 temp_frac = frac_val * 10;
2230                 buffer[prtn++] = '.';
2231                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
2232                         /* only reserved 2 bits fraction */
2233                         buffer[prtn++] ='0';
2234                         temp_frac *= 10;
2235                         frac_bits++;
2236                 }
2237                 /*
2238                  * Need to think these cases :
2239                  *      1. #echo x.00 > /proc/xxx       output result : x
2240                  *      2. #echo x.0x > /proc/xxx       output result : x.0x
2241                  *      3. #echo x.x0 > /proc/xxx       output result : x.x
2242                  *      4. #echo x.xx > /proc/xxx       output result : x.xx
2243                  *      Only reserved 2 bits fraction.
2244                  */
2245                 for (i = 0; i < (5 - prtn); i++)
2246                         temp_mult *= 10;
2247
2248                 frac_bits = min((int)count - prtn, 3 - frac_bits);
2249                 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
2250                                  frac_val * temp_mult / mult);
2251
2252                 prtn--;
2253                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
2254                         prtn--;
2255                         if (buffer[prtn] == '.') {
2256                                 prtn--;
2257                                 break;
2258                         }
2259                 }
2260                 prtn++;
2261         }
2262         buffer[prtn++] ='\n';
2263         return prtn;
2264 }
2265 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2266
2267 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
2268 {
2269         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
2270 }
2271 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2272
2273 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
2274                               __u64 *val, int mult)
2275 {
2276         char kernbuf[22], *end, *pbuf;
2277         __u64 whole, frac = 0, units;
2278         unsigned frac_d = 1;
2279
2280         if (count > (sizeof(kernbuf) - 1))
2281                 return -EINVAL;
2282
2283         if (cfs_copy_from_user(kernbuf, buffer, count))
2284                 return -EFAULT;
2285
2286         kernbuf[count] = '\0';
2287         pbuf = kernbuf;
2288         if (*pbuf == '-') {
2289                 mult = -mult;
2290                 pbuf++;
2291         }
2292
2293         whole = simple_strtoull(pbuf, &end, 10);
2294         if (pbuf == end)
2295                 return -EINVAL;
2296
2297         if (end != NULL && *end == '.') {
2298                 int i;
2299                 pbuf = end + 1;
2300
2301                 /* need to limit frac_d to a __u32 */
2302                 if (strlen(pbuf) > 10)
2303                         pbuf[10] = '\0';
2304
2305                 frac = simple_strtoull(pbuf, &end, 10);
2306                 /* count decimal places */
2307                 for (i = 0; i < (end - pbuf); i++)
2308                         frac_d *= 10;
2309         }
2310
2311         units = 1;
2312         switch(*end) {
2313         case 'p': case 'P':
2314                 units <<= 10;
2315         case 't': case 'T':
2316                 units <<= 10;
2317         case 'g': case 'G':
2318                 units <<= 10;
2319         case 'm': case 'M':
2320                 units <<= 10;
2321         case 'k': case 'K':
2322                 units <<= 10;
2323         }
2324         /* Specified units override the multiplier */
2325         if (units)
2326                 mult = mult < 0 ? -units : units;
2327
2328         frac *= mult;
2329         do_div(frac, frac_d);
2330         *val = whole * mult + frac;
2331         return 0;
2332 }
2333 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
2334
2335 static char *lprocfs_strnstr(const char *s1, const char *s2, size_t len)
2336 {
2337         size_t l2;
2338
2339         l2 = strlen(s2);
2340         if (!l2)
2341                 return (char *)s1;
2342         while (len >= l2) {
2343                 len--;
2344                 if (!memcmp(s1, s2, l2))
2345                         return (char *)s1;
2346                 s1++;
2347         }
2348         return NULL;
2349 }
2350
2351 /**
2352  * Find the string \a name in the input \a buffer, and return a pointer to the
2353  * value immediately following \a name, reducing \a count appropriately.
2354  * If \a name is not found the original \a buffer is returned.
2355  */
2356 char *lprocfs_find_named_value(const char *buffer, const char *name,
2357                                 unsigned long *count)
2358 {
2359         char *val;
2360         size_t buflen = *count;
2361
2362         /* there is no strnstr() in rhel5 and ubuntu kernels */
2363         val = lprocfs_strnstr(buffer, name, buflen);
2364         if (val == NULL)
2365                 return (char *)buffer;
2366
2367         val += strlen(name);                             /* skip prefix */
2368         while (val < buffer + buflen && isspace(*val)) /* skip separator */
2369                 val++;
2370
2371         *count = 0;
2372         while (val < buffer + buflen && isalnum(*val)) {
2373                 ++*count;
2374                 ++val;
2375         }
2376
2377         return val - *count;
2378 }
2379 EXPORT_SYMBOL(lprocfs_find_named_value);
2380
2381 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
2382                        const char *name,
2383                        mode_t mode,
2384                        const struct file_operations *seq_fops,
2385                        void *data)
2386 {
2387         struct proc_dir_entry *entry;
2388         ENTRY;
2389
2390         /* Disallow secretly (un)writable entries. */
2391         LASSERT((seq_fops->write == NULL) == ((mode & 0222) == 0));
2392
2393         LPROCFS_WRITE_ENTRY();
2394         entry = create_proc_entry(name, mode, parent);
2395         if (entry) {
2396                 entry->proc_fops = seq_fops;
2397                 entry->data = data;
2398         }
2399         LPROCFS_WRITE_EXIT();
2400
2401         if (entry == NULL)
2402                 RETURN(-ENOMEM);
2403
2404         RETURN(0);
2405 }
2406 EXPORT_SYMBOL(lprocfs_seq_create);
2407
2408 int lprocfs_obd_seq_create(struct obd_device *dev,
2409                            const char *name,
2410                            mode_t mode,
2411                            const struct file_operations *seq_fops,
2412                            void *data)
2413 {
2414         return (lprocfs_seq_create(dev->obd_proc_entry, name,
2415                                    mode, seq_fops, data));
2416 }
2417 EXPORT_SYMBOL(lprocfs_obd_seq_create);
2418
2419 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
2420 {
2421         if (value >= OBD_HIST_MAX)
2422                 value = OBD_HIST_MAX - 1;
2423
2424         spin_lock(&oh->oh_lock);
2425         oh->oh_buckets[value]++;
2426         spin_unlock(&oh->oh_lock);
2427 }
2428 EXPORT_SYMBOL(lprocfs_oh_tally);
2429
2430 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
2431 {
2432         unsigned int val;
2433
2434         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
2435                 ;
2436
2437         lprocfs_oh_tally(oh, val);
2438 }
2439 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
2440
2441 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
2442 {
2443         unsigned long ret = 0;
2444         int i;
2445
2446         for (i = 0; i < OBD_HIST_MAX; i++)
2447                 ret +=  oh->oh_buckets[i];
2448         return ret;
2449 }
2450 EXPORT_SYMBOL(lprocfs_oh_sum);
2451
2452 void lprocfs_oh_clear(struct obd_histogram *oh)
2453 {
2454         spin_lock(&oh->oh_lock);
2455         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
2456         spin_unlock(&oh->oh_lock);
2457 }
2458 EXPORT_SYMBOL(lprocfs_oh_clear);
2459
2460 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
2461                         int count, int *eof, void *data)
2462 {
2463         struct obd_device *obd = data;
2464         int c = 0;
2465
2466         if (obd == NULL)
2467                 return 0;
2468
2469         c += cfs_hash_debug_header(page, count);
2470         c += cfs_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2471         c += cfs_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2472         c += cfs_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2473
2474         return c;
2475 }
2476 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2477
2478 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2479                                    int count, int *eof, void *data)
2480 {
2481         struct obd_device *obd = data;
2482         int len = 0, size;
2483
2484         LASSERT(obd != NULL);
2485         LASSERT(count >= 0);
2486
2487         /* Set start of user data returned to
2488            page + off since the user may have
2489            requested to read much smaller than
2490            what we need to read */
2491         *start = page + off;
2492
2493         /* We know we are allocated a page here.
2494            Also we know that this function will
2495            not need to write more than a page
2496            so we can truncate at CFS_PAGE_SIZE.  */
2497         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
2498
2499         /* Initialize the page */
2500         memset(page, 0, size);
2501
2502         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2503                 goto out;
2504         if (obd->obd_max_recoverable_clients == 0) {
2505                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2506                         goto out;
2507
2508                 goto fclose;
2509         }
2510
2511         /* sampled unlocked, but really... */
2512         if (obd->obd_recovering == 0) {
2513                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2514                         goto out;
2515                 if (lprocfs_obd_snprintf(&page, size, &len,
2516                                          "recovery_start: %lu\n",
2517                                          obd->obd_recovery_start) <= 0)
2518                         goto out;
2519                 if (lprocfs_obd_snprintf(&page, size, &len,
2520                                          "recovery_duration: %lu\n",
2521                                          obd->obd_recovery_end -
2522                                          obd->obd_recovery_start) <= 0)
2523                         goto out;
2524                 /* Number of clients that have completed recovery */
2525                 if (lprocfs_obd_snprintf(&page, size, &len,
2526                                          "completed_clients: %d/%d\n",
2527                                          obd->obd_max_recoverable_clients -
2528                                          obd->obd_stale_clients,
2529                                          obd->obd_max_recoverable_clients) <= 0)
2530                         goto out;
2531                 if (lprocfs_obd_snprintf(&page, size, &len,
2532                                          "replayed_requests: %d\n",
2533                                          obd->obd_replayed_requests) <= 0)
2534                         goto out;
2535                 if (lprocfs_obd_snprintf(&page, size, &len,
2536                                          "last_transno: "LPD64"\n",
2537                                          obd->obd_next_recovery_transno - 1)<=0)
2538                         goto out;
2539                 if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
2540                                          obd->obd_version_recov ?
2541                                          "ENABLED" : "DISABLED") <=0)
2542                         goto out;
2543                 if (lprocfs_obd_snprintf(&page, size, &len, "IR: %s\n",
2544                                          obd->obd_no_ir ?
2545                                          "DISABLED" : "ENABLED") <= 0)
2546                         goto out;
2547                 goto fclose;
2548         }
2549
2550         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2551                 goto out;
2552         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2553                                  obd->obd_recovery_start) <= 0)
2554                 goto out;
2555         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2556                                  cfs_time_current_sec() >=
2557                                  obd->obd_recovery_start +
2558                                  obd->obd_recovery_timeout ? 0 :
2559                                  obd->obd_recovery_start +
2560                                  obd->obd_recovery_timeout -
2561                                  cfs_time_current_sec()) <= 0)
2562                 goto out;
2563         if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2564                                  cfs_atomic_read(&obd->obd_connected_clients),
2565                                  obd->obd_max_recoverable_clients) <= 0)
2566                 goto out;
2567         /* Number of clients that have completed recovery */
2568         if (lprocfs_obd_snprintf(&page, size, &len,"req_replay_clients: %d\n",
2569                                  cfs_atomic_read(&obd->obd_req_replay_clients))
2570                 <= 0)
2571                 goto out;
2572         if (lprocfs_obd_snprintf(&page, size, &len,"lock_repay_clients: %d\n",
2573                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2574                 <=0)
2575                 goto out;
2576         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d\n",
2577                                  cfs_atomic_read(&obd->obd_connected_clients) -
2578                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2579                 <=0)
2580                 goto out;
2581         if (lprocfs_obd_snprintf(&page, size, &len,"evicted_clients: %d\n",
2582                                  obd->obd_stale_clients) <= 0)
2583                 goto out;
2584         if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d\n",
2585                                  obd->obd_replayed_requests) <= 0)
2586                 goto out;
2587         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2588                                  obd->obd_requests_queued_for_recovery) <= 0)
2589                 goto out;
2590
2591         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2592                                  obd->obd_next_recovery_transno) <= 0)
2593                 goto out;
2594
2595 fclose:
2596         *eof = 1;
2597 out:
2598         return min(count, len - (int)off);
2599 }
2600 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2601
2602 int lprocfs_obd_rd_ir_factor(char *page, char **start, off_t off,
2603                              int count, int *eof, void *data)
2604 {
2605         struct obd_device *obd = (struct obd_device *)data;
2606         LASSERT(obd != NULL);
2607
2608         return snprintf(page, count, "%d\n",
2609                         obd->obd_recovery_ir_factor);
2610 }
2611 EXPORT_SYMBOL(lprocfs_obd_rd_ir_factor);
2612
2613 int lprocfs_obd_wr_ir_factor(struct file *file, const char *buffer,
2614                              unsigned long count, void *data)
2615 {
2616         struct obd_device *obd = (struct obd_device *)data;
2617         int val, rc;
2618         LASSERT(obd != NULL);
2619
2620         rc = lprocfs_write_helper(buffer, count, &val);
2621         if (rc)
2622                 return rc;
2623
2624         if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
2625                 return -EINVAL;
2626
2627         obd->obd_recovery_ir_factor = val;
2628         return count;
2629 }
2630 EXPORT_SYMBOL(lprocfs_obd_wr_ir_factor);
2631
2632 int lprocfs_obd_rd_recovery_time_soft(char *page, char **start, off_t off,
2633                                       int count, int *eof, void *data)
2634 {
2635         struct obd_device *obd = (struct obd_device *)data;
2636         LASSERT(obd != NULL);
2637
2638         return snprintf(page, count, "%d\n",
2639                         obd->obd_recovery_timeout);
2640 }
2641 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_soft);
2642
2643 int lprocfs_obd_wr_recovery_time_soft(struct file *file, const char *buffer,
2644                                       unsigned long count, void *data)
2645 {
2646         struct obd_device *obd = (struct obd_device *)data;
2647         int val, rc;
2648         LASSERT(obd != NULL);
2649
2650         rc = lprocfs_write_helper(buffer, count, &val);
2651         if (rc)
2652                 return rc;
2653
2654         obd->obd_recovery_timeout = val;
2655         return count;
2656 }
2657 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_soft);
2658
2659 int lprocfs_obd_rd_recovery_time_hard(char *page, char **start, off_t off,
2660                                       int count, int *eof, void *data)
2661 {
2662         struct obd_device *obd = data;
2663         LASSERT(obd != NULL);
2664
2665         return snprintf(page, count, "%u\n", obd->obd_recovery_time_hard);
2666 }
2667 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_hard);
2668
2669 int lprocfs_obd_wr_recovery_time_hard(struct file *file, const char *buffer,
2670                                       unsigned long count, void *data)
2671 {
2672         struct obd_device *obd = data;
2673         int val, rc;
2674         LASSERT(obd != NULL);
2675
2676         rc = lprocfs_write_helper(buffer, count, &val);
2677         if (rc)
2678                 return rc;
2679
2680         obd->obd_recovery_time_hard = val;
2681         return count;
2682 }
2683 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_hard);
2684
2685 int lprocfs_obd_rd_mntdev(char *page, char **start, off_t off,
2686                           int count, int *eof, void *data)
2687 {
2688         struct obd_device *obd = (struct obd_device *)data;
2689         struct lustre_mount_info *lmi;
2690         const char *dev_name;
2691
2692         LASSERT(obd != NULL);
2693         lmi = server_get_mount_2(obd->obd_name);
2694         dev_name = get_mntdev_name(lmi->lmi_sb);
2695         LASSERT(dev_name != NULL);
2696         *eof = 1;
2697         server_put_mount_2(obd->obd_name, lmi->lmi_mnt);
2698         return snprintf(page, count, "%s\n", dev_name);
2699 }
2700 EXPORT_SYMBOL(lprocfs_obd_rd_mntdev);
2701
2702 int lprocfs_obd_rd_max_pages_per_rpc(char *page, char **start, off_t off,
2703                                      int count, int *eof, void *data)
2704 {
2705         struct obd_device *dev = data;
2706         struct client_obd *cli = &dev->u.cli;
2707         int rc;
2708
2709         client_obd_list_lock(&cli->cl_loi_list_lock);
2710         rc = snprintf(page, count, "%d\n", cli->cl_max_pages_per_rpc);
2711         client_obd_list_unlock(&cli->cl_loi_list_lock);
2712         return rc;
2713 }
2714 EXPORT_SYMBOL(lprocfs_obd_rd_max_pages_per_rpc);
2715
2716 int lprocfs_target_rd_instance(char *page, char **start, off_t off,
2717                                int count, int *eof, void *data)
2718 {
2719         struct obd_device *obd = (struct obd_device *)data;
2720         struct obd_device_target *target = &obd->u.obt;
2721
2722         LASSERT(obd != NULL);
2723         LASSERT(target->obt_magic == OBT_MAGIC);
2724         *eof = 1;
2725         return snprintf(page, count, "%u\n", obd->u.obt.obt_instance);
2726 }
2727 EXPORT_SYMBOL(lprocfs_target_rd_instance);
2728 #endif /* LPROCFS*/