Whamcloud - gitweb
LU-1961 build: fix 'dereference before null check' errors
[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         struct lprocfs_counter *ptr;
869         unsigned int            num_entry;
870         int                     i;
871         unsigned long           flags = 0;
872
873         memset(cnt, 0, sizeof(*cnt));
874
875         if (stats == NULL) {
876                 /* set count to 1 to avoid divide-by-zero errs in callers */
877                 cnt->lc_count = 1;
878                 return;
879         }
880
881         cnt->lc_min = LC_MIN_INIT;
882
883         num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
884
885         for (i = 0; i < num_entry; i++) {
886                 if (stats->ls_percpu[i] == NULL)
887                         continue;
888
889                 ptr = &(stats->ls_percpu[i])->lp_cntr[idx];
890                 cnt->lc_count += ptr->lc_count;
891                 cnt->lc_sum += ptr->lc_sum;
892                 if (ptr->lc_min < cnt->lc_min)
893                         cnt->lc_min = ptr->lc_min;
894                 if (ptr->lc_max > cnt->lc_max)
895                         cnt->lc_max = ptr->lc_max;
896                 cnt->lc_sumsquare += ptr->lc_sumsquare;
897         }
898
899         cnt->lc_units = stats->ls_percpu[0]->lp_cntr[idx].lc_units;
900         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
901 }
902 EXPORT_SYMBOL(lprocfs_stats_collect);
903
904 /**
905  * Append a space separated list of current set flags to str.
906  */
907 #define flag2str(flag) \
908         if (imp->imp_##flag && max - len > 0) \
909              len += snprintf(str + len, max - len, "%s" #flag, len ? ", " : "");
910 static int obd_import_flags2str(struct obd_import *imp, char *str, int max)
911 {
912         int len = 0;
913
914         if (imp->imp_obd->obd_no_recov)
915                 len += snprintf(str, max - len, "no_recov");
916
917         flag2str(invalid);
918         flag2str(deactive);
919         flag2str(replayable);
920         flag2str(pingable);
921         return len;
922 }
923 #undef flags2str
924
925 static const char *obd_connect_names[] = {
926         "read_only",
927         "lov_index",
928         "unused",
929         "write_grant",
930         "server_lock",
931         "version",
932         "request_portal",
933         "acl",
934         "xattr",
935         "create_on_write",
936         "truncate_lock",
937         "initial_transno",
938         "inode_bit_locks",
939         "join_file(obsolete)",
940         "getattr_by_fid",
941         "no_oh_for_devices",
942         "remote_client",
943         "remote_client_by_force",
944         "max_byte_per_rpc",
945         "64bit_qdata",
946         "mds_capability",
947         "oss_capability",
948         "early_lock_cancel",
949         "som",
950         "adaptive_timeouts",
951         "lru_resize",
952         "mds_mds_connection",
953         "real_conn",
954         "change_qunit_size",
955         "alt_checksum_algorithm",
956         "fid_is_enabled",
957         "version_recovery",
958         "pools",
959         "grant_shrink",
960         "skip_orphan",
961         "large_ea",
962         "full20",
963         "layout_lock",
964         "64bithash",
965         "object_max_bytes",
966         "imp_recov",
967         "jobstats",
968         "umask",
969         "einprogress",
970         "grant_param",
971         "flock_owner",
972         "lvb_type",
973         "nanoseconds_times",
974         "lightweight_conn",
975         "short_io",
976         "unknown",
977         NULL
978 };
979
980 int obd_connect_flags2str(char *page, int count, __u64 flags, char *sep)
981 {
982         __u64 mask = 1;
983         int i, ret = 0;
984
985         for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
986                 if (flags & mask)
987                         ret += snprintf(page + ret, count - ret, "%s%s",
988                                         ret ? sep : "", obd_connect_names[i]);
989         }
990         if (flags & ~(mask - 1))
991                 ret += snprintf(page + ret, count - ret,
992                                 "%sunknown flags "LPX64,
993                                 ret ? sep : "", flags & ~(mask - 1));
994         return ret;
995 }
996 EXPORT_SYMBOL(obd_connect_flags2str);
997
998 int lprocfs_rd_import(char *page, char **start, off_t off, int count,
999                       int *eof, void *data)
1000 {
1001         struct lprocfs_counter ret;
1002         struct obd_device *obd = (struct obd_device *)data;
1003         struct obd_import *imp;
1004         struct obd_import_conn *conn;
1005         int i, j, k, rw = 0;
1006
1007         LASSERT(obd != NULL);
1008         LPROCFS_CLIMP_CHECK(obd);
1009         imp = obd->u.cli.cl_import;
1010         *eof = 1;
1011
1012         i = snprintf(page, count,
1013                      "import:\n"
1014                      "    name: %s\n"
1015                      "    target: %s\n"
1016                      "    state: %s\n"
1017                      "    instance: %u\n"
1018                      "    connect_flags: [",
1019                      obd->obd_name,
1020                      obd2cli_tgt(obd),
1021                      ptlrpc_import_state_name(imp->imp_state),
1022                      imp->imp_connect_data.ocd_instance);
1023         i += obd_connect_flags2str(page + i, count - i,
1024                                    imp->imp_connect_data.ocd_connect_flags,
1025                                    ", ");
1026         i += snprintf(page + i, count - i,
1027                       "]\n"
1028                       "    import_flags: [");
1029         i += obd_import_flags2str(imp, page + i, count - i);
1030
1031         i += snprintf(page + i, count - i,
1032                       "]\n"
1033                       "    connection:\n"
1034                       "       failover_nids: [");
1035         spin_lock(&imp->imp_lock);
1036         j = 0;
1037         cfs_list_for_each_entry(conn, &imp->imp_conn_list, oic_item) {
1038                 i += snprintf(page + i, count - i, "%s%s", j ? ", " : "",
1039                               libcfs_nid2str(conn->oic_conn->c_peer.nid));
1040                 j++;
1041         }
1042         i += snprintf(page + i, count - i,
1043                       "]\n"
1044                       "       current_connection: %s\n"
1045                       "       connection_attempts: %u\n"
1046                       "       generation: %u\n"
1047                       "       in-progress_invalidations: %u\n",
1048                       imp->imp_connection == NULL ? "<none>" :
1049                               libcfs_nid2str(imp->imp_connection->c_peer.nid),
1050                       imp->imp_conn_cnt,
1051                       imp->imp_generation,
1052                       cfs_atomic_read(&imp->imp_inval_count));
1053         spin_unlock(&imp->imp_lock);
1054
1055         lprocfs_stats_collect(obd->obd_svc_stats, PTLRPC_REQWAIT_CNTR, &ret);
1056         if (ret.lc_count != 0) {
1057                 /* first argument to do_div MUST be __u64 */
1058                 __u64 sum = ret.lc_sum;
1059                 do_div(sum, ret.lc_count);
1060                 ret.lc_sum = sum;
1061         } else
1062                 ret.lc_sum = 0;
1063         i += snprintf(page + i, count - i,
1064                       "    rpcs:\n"
1065                       "       inflight: %u\n"
1066                       "       unregistering: %u\n"
1067                       "       timeouts: %u\n"
1068                       "       avg_waittime: "LPU64" %s\n",
1069                       cfs_atomic_read(&imp->imp_inflight),
1070                       cfs_atomic_read(&imp->imp_unregistering),
1071                       cfs_atomic_read(&imp->imp_timeouts),
1072                       ret.lc_sum, ret.lc_units);
1073
1074         k = 0;
1075         for(j = 0; j < IMP_AT_MAX_PORTALS; j++) {
1076                 if (imp->imp_at.iat_portal[j] == 0)
1077                         break;
1078                 k = max_t(unsigned int, k,
1079                           at_get(&imp->imp_at.iat_service_estimate[j]));
1080         }
1081         i += snprintf(page + i, count - i,
1082                       "    service_estimates:\n"
1083                       "       services: %u sec\n"
1084                       "       network: %u sec\n",
1085                       k,
1086                       at_get(&imp->imp_at.iat_net_latency));
1087
1088         i += snprintf(page + i, count - i,
1089                       "    transactions:\n"
1090                       "       last_replay: "LPU64"\n"
1091                       "       peer_committed: "LPU64"\n"
1092                       "       last_checked: "LPU64"\n",
1093                       imp->imp_last_replay_transno,
1094                       imp->imp_peer_committed_transno,
1095                       imp->imp_last_transno_checked);
1096
1097         /* avg data rates */
1098         for (rw = 0; rw <= 1; rw++) {
1099                 lprocfs_stats_collect(obd->obd_svc_stats,
1100                                       PTLRPC_LAST_CNTR + BRW_READ_BYTES + rw,
1101                                       &ret);
1102                 if (ret.lc_sum > 0 && ret.lc_count > 0) {
1103                         /* first argument to do_div MUST be __u64 */
1104                         __u64 sum = ret.lc_sum;
1105                         do_div(sum, ret.lc_count);
1106                         ret.lc_sum = sum;
1107                         i += snprintf(page + i, count - i,
1108                                       "    %s_data_averages:\n"
1109                                       "       bytes_per_rpc: "LPU64"\n",
1110                                       rw ? "write" : "read",
1111                                       ret.lc_sum);
1112                 }
1113                 k = (int)ret.lc_sum;
1114                 j = opcode_offset(OST_READ + rw) + EXTRA_MAX_OPCODES;
1115                 lprocfs_stats_collect(obd->obd_svc_stats, j, &ret);
1116                 if (ret.lc_sum > 0 && ret.lc_count != 0) {
1117                         /* first argument to do_div MUST be __u64 */
1118                         __u64 sum = ret.lc_sum;
1119                         do_div(sum, ret.lc_count);
1120                         ret.lc_sum = sum;
1121                         i += snprintf(page + i, count - i,
1122                                       "       %s_per_rpc: "LPU64"\n",
1123                                       ret.lc_units, ret.lc_sum);
1124                         j = (int)ret.lc_sum;
1125                         if (j > 0)
1126                                 i += snprintf(page + i, count - i,
1127                                               "       MB_per_sec: %u.%.02u\n",
1128                                               k / j, (100 * k / j) % 100);
1129                 }
1130         }
1131
1132         LPROCFS_CLIMP_EXIT(obd);
1133         return i;
1134 }
1135 EXPORT_SYMBOL(lprocfs_rd_import);
1136
1137 int lprocfs_rd_state(char *page, char **start, off_t off, int count,
1138                       int *eof, void *data)
1139 {
1140         struct obd_device *obd = (struct obd_device *)data;
1141         struct obd_import *imp;
1142         int i, j, k;
1143
1144         LASSERT(obd != NULL);
1145         LPROCFS_CLIMP_CHECK(obd);
1146         imp = obd->u.cli.cl_import;
1147         *eof = 1;
1148
1149         i = snprintf(page, count, "current_state: %s\n",
1150                      ptlrpc_import_state_name(imp->imp_state));
1151         i += snprintf(page + i, count - i,
1152                       "state_history:\n");
1153         k = imp->imp_state_hist_idx;
1154         for (j = 0; j < IMP_STATE_HIST_LEN; j++) {
1155                 struct import_state_hist *ish =
1156                         &imp->imp_state_hist[(k + j) % IMP_STATE_HIST_LEN];
1157                 if (ish->ish_state == 0)
1158                         continue;
1159                 i += snprintf(page + i, count - i, " - ["CFS_TIME_T", %s]\n",
1160                               ish->ish_time,
1161                               ptlrpc_import_state_name(ish->ish_state));
1162         }
1163
1164         LPROCFS_CLIMP_EXIT(obd);
1165         return i;
1166 }
1167 EXPORT_SYMBOL(lprocfs_rd_state);
1168
1169 int lprocfs_at_hist_helper(char *page, int count, int rc,
1170                            struct adaptive_timeout *at)
1171 {
1172         int i;
1173         for (i = 0; i < AT_BINS; i++)
1174                 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
1175         rc += snprintf(page + rc, count - rc, "\n");
1176         return rc;
1177 }
1178 EXPORT_SYMBOL(lprocfs_at_hist_helper);
1179
1180 /* See also ptlrpc_lprocfs_rd_timeouts */
1181 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
1182                         int *eof, void *data)
1183 {
1184         struct obd_device *obd = (struct obd_device *)data;
1185         struct obd_import *imp;
1186         unsigned int cur, worst;
1187         time_t now, worstt;
1188         struct dhms ts;
1189         int i, rc = 0;
1190
1191         LASSERT(obd != NULL);
1192         LPROCFS_CLIMP_CHECK(obd);
1193         imp = obd->u.cli.cl_import;
1194         *eof = 1;
1195
1196         now = cfs_time_current_sec();
1197
1198         /* Some network health info for kicks */
1199         s2dhms(&ts, now - imp->imp_last_reply_time);
1200         rc += snprintf(page + rc, count - rc,
1201                        "%-10s : %ld, "DHMS_FMT" ago\n",
1202                        "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
1203
1204         cur = at_get(&imp->imp_at.iat_net_latency);
1205         worst = imp->imp_at.iat_net_latency.at_worst_ever;
1206         worstt = imp->imp_at.iat_net_latency.at_worst_time;
1207         s2dhms(&ts, now - worstt);
1208         rc += snprintf(page + rc, count - rc,
1209                        "%-10s : cur %3u  worst %3u (at %ld, "DHMS_FMT" ago) ",
1210                        "network", cur, worst, worstt, DHMS_VARS(&ts));
1211         rc = lprocfs_at_hist_helper(page, count, rc,
1212                                     &imp->imp_at.iat_net_latency);
1213
1214         for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
1215                 if (imp->imp_at.iat_portal[i] == 0)
1216                         break;
1217                 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
1218                 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
1219                 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
1220                 s2dhms(&ts, now - worstt);
1221                 rc += snprintf(page + rc, count - rc,
1222                                "portal %-2d  : cur %3u  worst %3u (at %ld, "
1223                                DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
1224                                cur, worst, worstt, DHMS_VARS(&ts));
1225                 rc = lprocfs_at_hist_helper(page, count, rc,
1226                                           &imp->imp_at.iat_service_estimate[i]);
1227         }
1228
1229         LPROCFS_CLIMP_EXIT(obd);
1230         return rc;
1231 }
1232 EXPORT_SYMBOL(lprocfs_rd_timeouts);
1233
1234 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
1235                              int count, int *eof, void *data)
1236 {
1237         struct obd_device *obd = data;
1238         __u64 flags;
1239         int ret = 0;
1240
1241         LPROCFS_CLIMP_CHECK(obd);
1242         flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
1243         ret = snprintf(page, count, "flags="LPX64"\n", flags);
1244         ret += obd_connect_flags2str(page + ret, count - ret, flags, "\n");
1245         ret += snprintf(page + ret, count - ret, "\n");
1246         LPROCFS_CLIMP_EXIT(obd);
1247         return ret;
1248 }
1249 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
1250
1251 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
1252                            int *eof,  void *data)
1253 {
1254         struct obd_device *obd = data;
1255
1256         LASSERT(obd != NULL);
1257         *eof = 1;
1258         return snprintf(page, count, "%u\n", obd->obd_num_exports);
1259 }
1260 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1261
1262 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
1263                        int *eof, void *data)
1264 {
1265         struct obd_type *class = (struct obd_type*) data;
1266
1267         LASSERT(class != NULL);
1268         *eof = 1;
1269         return snprintf(page, count, "%d\n", class->typ_refcnt);
1270 }
1271 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1272
1273 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
1274 {
1275         int rc = 0;
1276
1277         LASSERT(obd != NULL);
1278         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
1279         LASSERT(obd->obd_type->typ_procroot != NULL);
1280
1281         obd->obd_proc_entry = lprocfs_register(obd->obd_name,
1282                                                obd->obd_type->typ_procroot,
1283                                                list, obd);
1284         if (IS_ERR(obd->obd_proc_entry)) {
1285                 rc = PTR_ERR(obd->obd_proc_entry);
1286                 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
1287                 obd->obd_proc_entry = NULL;
1288         }
1289         return rc;
1290 }
1291 EXPORT_SYMBOL(lprocfs_obd_setup);
1292
1293 int lprocfs_obd_cleanup(struct obd_device *obd)
1294 {
1295         if (!obd)
1296                 return -EINVAL;
1297         if (obd->obd_proc_exports_entry) {
1298                 /* Should be no exports left */
1299                 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
1300                 lprocfs_remove(&obd->obd_proc_exports_entry);
1301                 obd->obd_proc_exports_entry = NULL;
1302         }
1303         if (obd->obd_proc_entry) {
1304                 lprocfs_remove(&obd->obd_proc_entry);
1305                 obd->obd_proc_entry = NULL;
1306         }
1307         return 0;
1308 }
1309 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1310
1311 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
1312 {
1313         CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
1314                client_stat->nid_proc, client_stat->nid_stats,
1315                client_stat->nid_brw_stats);
1316
1317         LASSERTF(cfs_atomic_read(&client_stat->nid_exp_ref_count) == 0,
1318                  "nid %s:count %d\n", libcfs_nid2str(client_stat->nid),
1319                  atomic_read(&client_stat->nid_exp_ref_count));
1320
1321         if (client_stat->nid_proc)
1322                 lprocfs_remove(&client_stat->nid_proc);
1323
1324         if (client_stat->nid_stats)
1325                 lprocfs_free_stats(&client_stat->nid_stats);
1326
1327         if (client_stat->nid_brw_stats)
1328                 OBD_FREE_PTR(client_stat->nid_brw_stats);
1329
1330         if (client_stat->nid_ldlm_stats)
1331                 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
1332
1333         OBD_FREE_PTR(client_stat);
1334         return;
1335
1336 }
1337
1338 void lprocfs_free_per_client_stats(struct obd_device *obd)
1339 {
1340         cfs_hash_t *hash = obd->obd_nid_stats_hash;
1341         struct nid_stat *stat;
1342         ENTRY;
1343
1344         /* we need extra list - because hash_exit called to early */
1345         /* not need locking because all clients is died */
1346         while (!cfs_list_empty(&obd->obd_nid_stats)) {
1347                 stat = cfs_list_entry(obd->obd_nid_stats.next,
1348                                       struct nid_stat, nid_list);
1349                 cfs_list_del_init(&stat->nid_list);
1350                 cfs_hash_del(hash, &stat->nid, &stat->nid_hash);
1351                 lprocfs_free_client_stats(stat);
1352         }
1353         EXIT;
1354 }
1355 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
1356
1357 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
1358                                           enum lprocfs_stats_flags flags)
1359 {
1360         struct lprocfs_stats *stats;
1361         unsigned int percpusize;
1362         unsigned int num_entry;
1363
1364         if (num == 0)
1365                 return NULL;
1366
1367         if (lprocfs_no_percpu_stats != 0)
1368                 flags |= LPROCFS_STATS_FLAG_NOPERCPU;
1369
1370         if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
1371                 num_entry = 1;
1372         else
1373                 num_entry = cfs_num_possible_cpus() + 1;
1374
1375         /* alloc percpu pointers for all possible cpu slots */
1376         OBD_ALLOC(stats, offsetof(struct lprocfs_stats, ls_percpu[num_entry]));
1377         if (stats == NULL)
1378                 return NULL;
1379
1380         stats->ls_num = num;
1381         stats->ls_biggest_alloc_num = 1;
1382         stats->ls_flags = flags;
1383         spin_lock_init(&stats->ls_lock);
1384
1385         percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
1386         if (num_entry > 1)
1387                 percpusize = CFS_L1_CACHE_ALIGN(percpusize);
1388
1389         /* for no percpu area, the 0th entry is for real use,
1390          * for percpu area, the 0th entry is for intialized entry template */
1391         OBD_ALLOC(stats->ls_percpu[0], percpusize);
1392         if (stats->ls_percpu[0] == NULL) {
1393                 OBD_FREE(stats,
1394                          offsetof(struct lprocfs_stats, ls_percpu[num_entry]));
1395                 stats = NULL;
1396         }
1397         return stats;
1398 }
1399 EXPORT_SYMBOL(lprocfs_alloc_stats);
1400
1401 void lprocfs_free_stats(struct lprocfs_stats **statsh)
1402 {
1403         struct lprocfs_stats *stats = *statsh;
1404         unsigned int num_entry;
1405         unsigned int percpusize;
1406         unsigned int i;
1407
1408         if (stats == NULL || stats->ls_num == 0)
1409                 return;
1410         *statsh = NULL;
1411
1412         if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1413                 num_entry = 1;
1414         else
1415                 num_entry = cfs_num_possible_cpus() + 1;
1416
1417         percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
1418         if (num_entry > 1)
1419                 percpusize = CFS_L1_CACHE_ALIGN(percpusize);
1420         for (i = 0; i < num_entry; i++)
1421                 if (stats->ls_percpu[i] != NULL)
1422                         OBD_FREE(stats->ls_percpu[i], percpusize);
1423         OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_entry]));
1424 }
1425 EXPORT_SYMBOL(lprocfs_free_stats);
1426
1427 void lprocfs_clear_stats(struct lprocfs_stats *stats)
1428 {
1429         struct lprocfs_counter *percpu_cntr;
1430         int                     i;
1431         int                     j;
1432         unsigned int            num_entry;
1433         unsigned long           flags = 0;
1434
1435         num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
1436
1437         for (i = 0; i < num_entry; i++) {
1438                 if (stats->ls_percpu[i] == NULL)
1439                         continue;
1440                 for (j = 0; j < stats->ls_num; j++) {
1441                         percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
1442                         percpu_cntr->lc_count = 0;
1443                         percpu_cntr->lc_sum = 0;
1444                         percpu_cntr->lc_min = LC_MIN_INIT;
1445                         percpu_cntr->lc_max = 0;
1446                         percpu_cntr->lc_sumsquare = 0;
1447                 }
1448         }
1449
1450         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
1451 }
1452 EXPORT_SYMBOL(lprocfs_clear_stats);
1453
1454 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
1455                                        size_t len, loff_t *off)
1456 {
1457         struct seq_file *seq = file->private_data;
1458         struct lprocfs_stats *stats = seq->private;
1459
1460         lprocfs_clear_stats(stats);
1461
1462         return len;
1463 }
1464
1465 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
1466 {
1467         struct lprocfs_stats *stats = p->private;
1468         /* return 1st cpu location */
1469         return (*pos >= stats->ls_num) ? NULL :
1470                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1471 }
1472
1473 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1474 {
1475 }
1476
1477 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1478 {
1479         struct lprocfs_stats *stats = p->private;
1480         ++*pos;
1481         return (*pos >= stats->ls_num) ? NULL :
1482                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1483 }
1484
1485 /* seq file export of one lprocfs counter */
1486 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1487 {
1488        struct lprocfs_stats *stats = p->private;
1489        struct lprocfs_counter *cntr = v;
1490        struct lprocfs_counter ret;
1491        int idx, rc = 0;
1492
1493        if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
1494                struct timeval now;
1495                cfs_gettimeofday(&now);
1496                rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1497                                "snapshot_time", now.tv_sec, now.tv_usec);
1498                if (rc < 0)
1499                        return rc;
1500        }
1501        idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
1502
1503        lprocfs_stats_collect(stats, idx, &ret);
1504
1505        if (ret.lc_count == 0)
1506                goto out;
1507
1508        rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
1509                        ret.lc_count, cntr->lc_units);
1510
1511        if (rc < 0)
1512                goto out;
1513
1514        if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
1515                rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1516                                ret.lc_min, ret.lc_max, ret.lc_sum);
1517                if (rc < 0)
1518                        goto out;
1519                if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
1520                        rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1521                if (rc < 0)
1522                        goto out;
1523        }
1524        rc = seq_printf(p, "\n");
1525  out:
1526        return (rc < 0) ? rc : 0;
1527 }
1528
1529 struct seq_operations lprocfs_stats_seq_sops = {
1530         start: lprocfs_stats_seq_start,
1531         stop:  lprocfs_stats_seq_stop,
1532         next:  lprocfs_stats_seq_next,
1533         show:  lprocfs_stats_seq_show,
1534 };
1535
1536 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1537 {
1538         struct proc_dir_entry *dp = PDE(inode);
1539         struct seq_file *seq;
1540         int rc;
1541
1542         if (LPROCFS_ENTRY_AND_CHECK(dp))
1543                 return -ENOENT;
1544
1545         rc = seq_open(file, &lprocfs_stats_seq_sops);
1546         if (rc) {
1547                 LPROCFS_EXIT();
1548                 return rc;
1549         }
1550         seq = file->private_data;
1551         seq->private = dp->data;
1552         return 0;
1553 }
1554
1555 struct file_operations lprocfs_stats_seq_fops = {
1556         .owner   = THIS_MODULE,
1557         .open    = lprocfs_stats_seq_open,
1558         .read    = seq_read,
1559         .write   = lprocfs_stats_seq_write,
1560         .llseek  = seq_lseek,
1561         .release = lprocfs_seq_release,
1562 };
1563
1564 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1565                            struct lprocfs_stats *stats)
1566 {
1567         struct proc_dir_entry *entry;
1568         LASSERT(root != NULL);
1569
1570         LPROCFS_WRITE_ENTRY();
1571         entry = create_proc_entry(name, 0644, root);
1572         if (entry) {
1573                 entry->proc_fops = &lprocfs_stats_seq_fops;
1574                 entry->data = stats;
1575         }
1576
1577         LPROCFS_WRITE_EXIT();
1578
1579         if (entry == NULL)
1580                 return -ENOMEM;
1581
1582         return 0;
1583 }
1584 EXPORT_SYMBOL(lprocfs_register_stats);
1585
1586 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1587                           unsigned conf, const char *name, const char *units)
1588 {
1589         struct lprocfs_counter *c;
1590         unsigned long           flags = 0;
1591
1592         LASSERT(stats != NULL);
1593         LASSERT(stats->ls_percpu[0] != NULL);
1594
1595         c = &(stats->ls_percpu[0]->lp_cntr[index]);
1596
1597         lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
1598         c->lc_config = conf;
1599         c->lc_count = 0;
1600         c->lc_sum = 0;
1601         c->lc_min = LC_MIN_INIT;
1602         c->lc_max = 0;
1603         c->lc_name = name;
1604         c->lc_units = units;
1605         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
1606 }
1607 EXPORT_SYMBOL(lprocfs_counter_init);
1608
1609 #define LPROCFS_OBD_OP_INIT(base, stats, op)                               \
1610 do {                                                                       \
1611         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);              \
1612         LASSERT(coffset < stats->ls_num);                                  \
1613         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");              \
1614 } while (0)
1615
1616 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1617 {
1618         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1619         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1620         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1621         LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1622         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1623         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1624         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1625         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1626         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1627         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1628         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1629         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1630         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1631         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1632         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1633         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1634         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1635         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1636         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1637         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1638         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1639         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1640         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1641         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1642         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1643         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create_async);
1644         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1645         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1646         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1647         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1648         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1649         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1650         LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1651         LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1652         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1653         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1654         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1655         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1656         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1657         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1658         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1659         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1660         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1661         LPROCFS_OBD_OP_INIT(num_private_stats, stats, find_cbdata);
1662         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1663         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1664         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1665         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1666         LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1667         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1668         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1669         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1670         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1671         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1672         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1673         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1674         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1675         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
1676         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1677         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1678         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1679         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1680         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1681         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1682         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1683         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
1684         LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
1685 }
1686 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1687
1688 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1689 {
1690         struct lprocfs_stats *stats;
1691         unsigned int num_stats;
1692         int rc, i;
1693
1694         LASSERT(obd->obd_stats == NULL);
1695         LASSERT(obd->obd_proc_entry != NULL);
1696         LASSERT(obd->obd_cntr_base == 0);
1697
1698         num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1699                 num_private_stats - 1 /* o_owner */;
1700         stats = lprocfs_alloc_stats(num_stats, 0);
1701         if (stats == NULL)
1702                 return -ENOMEM;
1703
1704         lprocfs_init_ops_stats(num_private_stats, stats);
1705
1706         for (i = num_private_stats; i < num_stats; i++) {
1707                 /* If this LBUGs, it is likely that an obd
1708                  * operation was added to struct obd_ops in
1709                  * <obd.h>, and that the corresponding line item
1710                  * LPROCFS_OBD_OP_INIT(.., .., opname)
1711                  * is missing from the list above. */
1712                 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1713                          "Missing obd_stat initializer obd_op "
1714                          "operation at offset %d.\n", i - num_private_stats);
1715         }
1716         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1717         if (rc < 0) {
1718                 lprocfs_free_stats(&stats);
1719         } else {
1720                 obd->obd_stats  = stats;
1721                 obd->obd_cntr_base = num_private_stats;
1722         }
1723         return rc;
1724 }
1725 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1726
1727 void lprocfs_free_obd_stats(struct obd_device *obd)
1728 {
1729         if (obd->obd_stats)
1730                 lprocfs_free_stats(&obd->obd_stats);
1731 }
1732 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1733
1734 #define LPROCFS_MD_OP_INIT(base, stats, op)                             \
1735 do {                                                                    \
1736         unsigned int coffset = base + MD_COUNTER_OFFSET(op);            \
1737         LASSERT(coffset < stats->ls_num);                               \
1738         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
1739 } while (0)
1740
1741 void lprocfs_init_mps_stats(int num_private_stats, struct lprocfs_stats *stats)
1742 {
1743         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1744         LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1745         LPROCFS_MD_OP_INIT(num_private_stats, stats, find_cbdata);
1746         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1747         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1748         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1749         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1750         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1751         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1752         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1753         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1754         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1755         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1756         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1757         LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1758         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1759         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1760         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1761         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1762         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1763         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1764         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1765         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1766         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1767         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1768         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1769         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1770         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1771         LPROCFS_MD_OP_INIT(num_private_stats, stats, unpack_capa);
1772         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1773         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1774         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1775 }
1776 EXPORT_SYMBOL(lprocfs_init_mps_stats);
1777
1778 int lprocfs_alloc_md_stats(struct obd_device *obd,
1779                            unsigned num_private_stats)
1780 {
1781         struct lprocfs_stats *stats;
1782         unsigned int num_stats;
1783         int rc, i;
1784
1785         LASSERT(obd->md_stats == NULL);
1786         LASSERT(obd->obd_proc_entry != NULL);
1787         LASSERT(obd->md_cntr_base == 0);
1788
1789         num_stats = 1 + MD_COUNTER_OFFSET(revalidate_lock) +
1790                     num_private_stats;
1791         stats = lprocfs_alloc_stats(num_stats, 0);
1792         if (stats == NULL)
1793                 return -ENOMEM;
1794
1795         lprocfs_init_mps_stats(num_private_stats, stats);
1796
1797         for (i = num_private_stats; i < num_stats; i++) {
1798                 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1799                         CERROR("Missing md_stat initializer md_op "
1800                                "operation at offset %d. Aborting.\n",
1801                                i - num_private_stats);
1802                         LBUG();
1803                 }
1804         }
1805         rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
1806         if (rc < 0) {
1807                 lprocfs_free_stats(&stats);
1808         } else {
1809                 obd->md_stats  = stats;
1810                 obd->md_cntr_base = num_private_stats;
1811         }
1812         return rc;
1813 }
1814 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
1815
1816 void lprocfs_free_md_stats(struct obd_device *obd)
1817 {
1818         struct lprocfs_stats *stats = obd->md_stats;
1819
1820         if (stats != NULL) {
1821                 obd->md_stats = NULL;
1822                 obd->md_cntr_base = 0;
1823                 lprocfs_free_stats(&stats);
1824         }
1825 }
1826 EXPORT_SYMBOL(lprocfs_free_md_stats);
1827
1828 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1829 {
1830         lprocfs_counter_init(ldlm_stats,
1831                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
1832                              0, "ldlm_enqueue", "reqs");
1833         lprocfs_counter_init(ldlm_stats,
1834                              LDLM_CONVERT - LDLM_FIRST_OPC,
1835                              0, "ldlm_convert", "reqs");
1836         lprocfs_counter_init(ldlm_stats,
1837                              LDLM_CANCEL - LDLM_FIRST_OPC,
1838                              0, "ldlm_cancel", "reqs");
1839         lprocfs_counter_init(ldlm_stats,
1840                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1841                              0, "ldlm_bl_callback", "reqs");
1842         lprocfs_counter_init(ldlm_stats,
1843                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1844                              0, "ldlm_cp_callback", "reqs");
1845         lprocfs_counter_init(ldlm_stats,
1846                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1847                              0, "ldlm_gl_callback", "reqs");
1848 }
1849 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
1850
1851 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1852                          int *eof,  void *data)
1853 {
1854         struct obd_export *exp = data;
1855         LASSERT(exp != NULL);
1856         *eof = 1;
1857         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1858 }
1859
1860 struct exp_uuid_cb_data {
1861         char                   *page;
1862         int                     count;
1863         int                    *eof;
1864         int                    *len;
1865 };
1866
1867 static void
1868 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1869                             int count, int *eof, int *len)
1870 {
1871         cb_data->page = page;
1872         cb_data->count = count;
1873         cb_data->eof = eof;
1874         cb_data->len = len;
1875 }
1876
1877 int lprocfs_exp_print_uuid(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1878                            cfs_hlist_node_t *hnode, void *cb_data)
1879
1880 {
1881         struct obd_export *exp = cfs_hash_object(hs, hnode);
1882         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1883
1884         if (exp->exp_nid_stats)
1885                 *data->len += snprintf((data->page + *data->len),
1886                                        data->count, "%s\n",
1887                                        obd_uuid2str(&exp->exp_client_uuid));
1888         return 0;
1889 }
1890
1891 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1892                         int *eof,  void *data)
1893 {
1894         struct nid_stat *stats = (struct nid_stat *)data;
1895         struct exp_uuid_cb_data cb_data;
1896         struct obd_device *obd = stats->nid_obd;
1897         int len = 0;
1898
1899         *eof = 1;
1900         page[0] = '\0';
1901         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1902         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1903                               lprocfs_exp_print_uuid, &cb_data);
1904         return (*cb_data.len);
1905 }
1906
1907 int lprocfs_exp_print_hash(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1908                            cfs_hlist_node_t *hnode, void *cb_data)
1909
1910 {
1911         struct exp_uuid_cb_data *data = cb_data;
1912         struct obd_export       *exp = cfs_hash_object(hs, hnode);
1913
1914         if (exp->exp_lock_hash != NULL) {
1915                 if (!*data->len) {
1916                         *data->len += cfs_hash_debug_header(data->page,
1917                                                             data->count);
1918                 }
1919                 *data->len += cfs_hash_debug_str(hs, data->page + *data->len,
1920                                                  data->count);
1921         }
1922
1923         return 0;
1924 }
1925
1926 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1927                         int *eof,  void *data)
1928 {
1929         struct nid_stat *stats = (struct nid_stat *)data;
1930         struct exp_uuid_cb_data cb_data;
1931         struct obd_device *obd = stats->nid_obd;
1932         int len = 0;
1933
1934         *eof = 1;
1935         page[0] = '\0';
1936         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1937
1938         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1939                               lprocfs_exp_print_hash, &cb_data);
1940         return (*cb_data.len);
1941 }
1942
1943 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1944                                         int count, int *eof,  void *data)
1945 {
1946         *eof = 1;
1947         return snprintf(page, count, "%s\n",
1948                         "Write into this file to clear all nid stats and "
1949                         "stale nid entries");
1950 }
1951 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1952
1953 static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1954 {
1955         struct nid_stat *stat = obj;
1956         int i;
1957         ENTRY;
1958
1959         CDEBUG(D_INFO,"refcnt %d\n", cfs_atomic_read(&stat->nid_exp_ref_count));
1960         if (cfs_atomic_read(&stat->nid_exp_ref_count) == 1) {
1961                 /* object has only hash references. */
1962                 spin_lock(&stat->nid_obd->obd_nid_lock);
1963                 cfs_list_move(&stat->nid_list, data);
1964                 spin_unlock(&stat->nid_obd->obd_nid_lock);
1965                 RETURN(1);
1966         }
1967         /* we has reference to object - only clear data*/
1968         if (stat->nid_stats)
1969                 lprocfs_clear_stats(stat->nid_stats);
1970
1971         if (stat->nid_brw_stats) {
1972                 for (i = 0; i < BRW_LAST; i++)
1973                         lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1974         }
1975         RETURN(0);
1976 }
1977
1978 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1979                                   unsigned long count, void *data)
1980 {
1981         struct obd_device *obd = (struct obd_device *)data;
1982         struct nid_stat *client_stat;
1983         CFS_LIST_HEAD(free_list);
1984
1985         cfs_hash_cond_del(obd->obd_nid_stats_hash,
1986                           lprocfs_nid_stats_clear_write_cb, &free_list);
1987
1988         while (!cfs_list_empty(&free_list)) {
1989                 client_stat = cfs_list_entry(free_list.next, struct nid_stat,
1990                                              nid_list);
1991                 cfs_list_del_init(&client_stat->nid_list);
1992                 lprocfs_free_client_stats(client_stat);
1993         }
1994
1995         return count;
1996 }
1997 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1998
1999 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
2000 {
2001         struct nid_stat *new_stat, *old_stat;
2002         struct obd_device *obd = NULL;
2003         cfs_proc_dir_entry_t *entry;
2004         char *buffer = NULL;
2005         int rc = 0;
2006         ENTRY;
2007
2008         *newnid = 0;
2009
2010         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
2011             !exp->exp_obd->obd_nid_stats_hash)
2012                 RETURN(-EINVAL);
2013
2014         /* not test against zero because eric say:
2015          * You may only test nid against another nid, or LNET_NID_ANY.
2016          * Anything else is nonsense.*/
2017         if (!nid || *nid == LNET_NID_ANY)
2018                 RETURN(0);
2019
2020         obd = exp->exp_obd;
2021
2022         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
2023
2024         OBD_ALLOC_PTR(new_stat);
2025         if (new_stat == NULL)
2026                 RETURN(-ENOMEM);
2027
2028         new_stat->nid               = *nid;
2029         new_stat->nid_obd           = exp->exp_obd;
2030         /* we need set default refcount to 1 to balance obd_disconnect */
2031         cfs_atomic_set(&new_stat->nid_exp_ref_count, 1);
2032
2033         old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
2034                                            nid, &new_stat->nid_hash);
2035         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
2036                old_stat, libcfs_nid2str(*nid),
2037                cfs_atomic_read(&new_stat->nid_exp_ref_count));
2038
2039         /* We need to release old stats because lprocfs_exp_cleanup() hasn't
2040          * been and will never be called. */
2041         if (exp->exp_nid_stats) {
2042                 nidstat_putref(exp->exp_nid_stats);
2043                 exp->exp_nid_stats = NULL;
2044         }
2045
2046         /* Return -EALREADY here so that we know that the /proc
2047          * entry already has been created */
2048         if (old_stat != new_stat) {
2049                 exp->exp_nid_stats = old_stat;
2050                 GOTO(destroy_new, rc = -EALREADY);
2051         }
2052         /* not found - create */
2053         OBD_ALLOC(buffer, LNET_NIDSTR_SIZE);
2054         if (buffer == NULL)
2055                 GOTO(destroy_new, rc = -ENOMEM);
2056
2057         memcpy(buffer, libcfs_nid2str(*nid), LNET_NIDSTR_SIZE);
2058         new_stat->nid_proc = lprocfs_register(buffer,
2059                                               obd->obd_proc_exports_entry,
2060                                               NULL, NULL);
2061         OBD_FREE(buffer, LNET_NIDSTR_SIZE);
2062
2063         if (new_stat->nid_proc == NULL) {
2064                 CERROR("Error making export directory for nid %s\n",
2065                        libcfs_nid2str(*nid));
2066                 GOTO(destroy_new_ns, rc = -ENOMEM);
2067         }
2068
2069         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
2070                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
2071         if (IS_ERR(entry)) {
2072                 CWARN("Error adding the NID stats file\n");
2073                 rc = PTR_ERR(entry);
2074                 GOTO(destroy_new_ns, rc);
2075         }
2076
2077         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
2078                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
2079         if (IS_ERR(entry)) {
2080                 CWARN("Error adding the hash file\n");
2081                 rc = PTR_ERR(entry);
2082                 GOTO(destroy_new_ns, rc);
2083         }
2084
2085         exp->exp_nid_stats = new_stat;
2086         *newnid = 1;
2087         /* protect competitive add to list, not need locking on destroy */
2088         spin_lock(&obd->obd_nid_lock);
2089         cfs_list_add(&new_stat->nid_list, &obd->obd_nid_stats);
2090         spin_unlock(&obd->obd_nid_lock);
2091
2092         RETURN(rc);
2093
2094 destroy_new_ns:
2095         if (new_stat->nid_proc != NULL)
2096                 lprocfs_remove(&new_stat->nid_proc);
2097         cfs_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
2098
2099 destroy_new:
2100         nidstat_putref(new_stat);
2101         OBD_FREE_PTR(new_stat);
2102         RETURN(rc);
2103 }
2104 EXPORT_SYMBOL(lprocfs_exp_setup);
2105
2106 int lprocfs_exp_cleanup(struct obd_export *exp)
2107 {
2108         struct nid_stat *stat = exp->exp_nid_stats;
2109
2110         if(!stat || !exp->exp_obd)
2111                 RETURN(0);
2112
2113         nidstat_putref(exp->exp_nid_stats);
2114         exp->exp_nid_stats = NULL;
2115
2116         return 0;
2117 }
2118 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2119
2120 int lprocfs_write_helper(const char *buffer, unsigned long count,
2121                          int *val)
2122 {
2123         return lprocfs_write_frac_helper(buffer, count, val, 1);
2124 }
2125 EXPORT_SYMBOL(lprocfs_write_helper);
2126
2127 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
2128                               int *val, int mult)
2129 {
2130         char kernbuf[20], *end, *pbuf;
2131
2132         if (count > (sizeof(kernbuf) - 1))
2133                 return -EINVAL;
2134
2135         if (cfs_copy_from_user(kernbuf, buffer, count))
2136                 return -EFAULT;
2137
2138         kernbuf[count] = '\0';
2139         pbuf = kernbuf;
2140         if (*pbuf == '-') {
2141                 mult = -mult;
2142                 pbuf++;
2143         }
2144
2145         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2146         if (pbuf == end)
2147                 return -EINVAL;
2148
2149         if (end != NULL && *end == '.') {
2150                 int temp_val, pow = 1;
2151                 int i;
2152
2153                 pbuf = end + 1;
2154                 if (strlen(pbuf) > 5)
2155                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
2156
2157                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2158
2159                 if (pbuf < end) {
2160                         for (i = 0; i < (end - pbuf); i++)
2161                                 pow *= 10;
2162
2163                         *val += temp_val / pow;
2164                 }
2165         }
2166         return 0;
2167 }
2168 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2169
2170 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
2171                              int mult)
2172 {
2173         long decimal_val, frac_val;
2174         int prtn;
2175
2176         if (count < 10)
2177                 return -EINVAL;
2178
2179         decimal_val = val / mult;
2180         prtn = snprintf(buffer, count, "%ld", decimal_val);
2181         frac_val = val % mult;
2182
2183         if (prtn < (count - 4) && frac_val > 0) {
2184                 long temp_frac;
2185                 int i, temp_mult = 1, frac_bits = 0;
2186
2187                 temp_frac = frac_val * 10;
2188                 buffer[prtn++] = '.';
2189                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
2190                         /* only reserved 2 bits fraction */
2191                         buffer[prtn++] ='0';
2192                         temp_frac *= 10;
2193                         frac_bits++;
2194                 }
2195                 /*
2196                  * Need to think these cases :
2197                  *      1. #echo x.00 > /proc/xxx       output result : x
2198                  *      2. #echo x.0x > /proc/xxx       output result : x.0x
2199                  *      3. #echo x.x0 > /proc/xxx       output result : x.x
2200                  *      4. #echo x.xx > /proc/xxx       output result : x.xx
2201                  *      Only reserved 2 bits fraction.
2202                  */
2203                 for (i = 0; i < (5 - prtn); i++)
2204                         temp_mult *= 10;
2205
2206                 frac_bits = min((int)count - prtn, 3 - frac_bits);
2207                 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
2208                                  frac_val * temp_mult / mult);
2209
2210                 prtn--;
2211                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
2212                         prtn--;
2213                         if (buffer[prtn] == '.') {
2214                                 prtn--;
2215                                 break;
2216                         }
2217                 }
2218                 prtn++;
2219         }
2220         buffer[prtn++] ='\n';
2221         return prtn;
2222 }
2223 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2224
2225 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
2226 {
2227         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
2228 }
2229 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2230
2231 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
2232                               __u64 *val, int mult)
2233 {
2234         char kernbuf[22], *end, *pbuf;
2235         __u64 whole, frac = 0, units;
2236         unsigned frac_d = 1;
2237
2238         if (count > (sizeof(kernbuf) - 1))
2239                 return -EINVAL;
2240
2241         if (cfs_copy_from_user(kernbuf, buffer, count))
2242                 return -EFAULT;
2243
2244         kernbuf[count] = '\0';
2245         pbuf = kernbuf;
2246         if (*pbuf == '-') {
2247                 mult = -mult;
2248                 pbuf++;
2249         }
2250
2251         whole = simple_strtoull(pbuf, &end, 10);
2252         if (pbuf == end)
2253                 return -EINVAL;
2254
2255         if (end != NULL && *end == '.') {
2256                 int i;
2257                 pbuf = end + 1;
2258
2259                 /* need to limit frac_d to a __u32 */
2260                 if (strlen(pbuf) > 10)
2261                         pbuf[10] = '\0';
2262
2263                 frac = simple_strtoull(pbuf, &end, 10);
2264                 /* count decimal places */
2265                 for (i = 0; i < (end - pbuf); i++)
2266                         frac_d *= 10;
2267         }
2268
2269         units = 1;
2270         switch(*end) {
2271         case 'p': case 'P':
2272                 units <<= 10;
2273         case 't': case 'T':
2274                 units <<= 10;
2275         case 'g': case 'G':
2276                 units <<= 10;
2277         case 'm': case 'M':
2278                 units <<= 10;
2279         case 'k': case 'K':
2280                 units <<= 10;
2281         }
2282         /* Specified units override the multiplier */
2283         if (units)
2284                 mult = mult < 0 ? -units : units;
2285
2286         frac *= mult;
2287         do_div(frac, frac_d);
2288         *val = whole * mult + frac;
2289         return 0;
2290 }
2291 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
2292
2293 static char *lprocfs_strnstr(const char *s1, const char *s2, size_t len)
2294 {
2295         size_t l2;
2296
2297         l2 = strlen(s2);
2298         if (!l2)
2299                 return (char *)s1;
2300         while (len >= l2) {
2301                 len--;
2302                 if (!memcmp(s1, s2, l2))
2303                         return (char *)s1;
2304                 s1++;
2305         }
2306         return NULL;
2307 }
2308
2309 /**
2310  * Find the string \a name in the input \a buffer, and return a pointer to the
2311  * value immediately following \a name, reducing \a count appropriately.
2312  * If \a name is not found the original \a buffer is returned.
2313  */
2314 char *lprocfs_find_named_value(const char *buffer, const char *name,
2315                                 unsigned long *count)
2316 {
2317         char *val;
2318         size_t buflen = *count;
2319
2320         /* there is no strnstr() in rhel5 and ubuntu kernels */
2321         val = lprocfs_strnstr(buffer, name, buflen);
2322         if (val == NULL)
2323                 return (char *)buffer;
2324
2325         val += strlen(name);                             /* skip prefix */
2326         while (val < buffer + buflen && isspace(*val)) /* skip separator */
2327                 val++;
2328
2329         *count = 0;
2330         while (val < buffer + buflen && isalnum(*val)) {
2331                 ++*count;
2332                 ++val;
2333         }
2334
2335         return val - *count;
2336 }
2337 EXPORT_SYMBOL(lprocfs_find_named_value);
2338
2339 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
2340                        const char *name,
2341                        mode_t mode,
2342                        const struct file_operations *seq_fops,
2343                        void *data)
2344 {
2345         struct proc_dir_entry *entry;
2346         ENTRY;
2347
2348         /* Disallow secretly (un)writable entries. */
2349         LASSERT((seq_fops->write == NULL) == ((mode & 0222) == 0));
2350
2351         LPROCFS_WRITE_ENTRY();
2352         entry = create_proc_entry(name, mode, parent);
2353         if (entry) {
2354                 entry->proc_fops = seq_fops;
2355                 entry->data = data;
2356         }
2357         LPROCFS_WRITE_EXIT();
2358
2359         if (entry == NULL)
2360                 RETURN(-ENOMEM);
2361
2362         RETURN(0);
2363 }
2364 EXPORT_SYMBOL(lprocfs_seq_create);
2365
2366 int lprocfs_obd_seq_create(struct obd_device *dev,
2367                            const char *name,
2368                            mode_t mode,
2369                            const struct file_operations *seq_fops,
2370                            void *data)
2371 {
2372         return (lprocfs_seq_create(dev->obd_proc_entry, name,
2373                                    mode, seq_fops, data));
2374 }
2375 EXPORT_SYMBOL(lprocfs_obd_seq_create);
2376
2377 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
2378 {
2379         if (value >= OBD_HIST_MAX)
2380                 value = OBD_HIST_MAX - 1;
2381
2382         spin_lock(&oh->oh_lock);
2383         oh->oh_buckets[value]++;
2384         spin_unlock(&oh->oh_lock);
2385 }
2386 EXPORT_SYMBOL(lprocfs_oh_tally);
2387
2388 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
2389 {
2390         unsigned int val;
2391
2392         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
2393                 ;
2394
2395         lprocfs_oh_tally(oh, val);
2396 }
2397 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
2398
2399 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
2400 {
2401         unsigned long ret = 0;
2402         int i;
2403
2404         for (i = 0; i < OBD_HIST_MAX; i++)
2405                 ret +=  oh->oh_buckets[i];
2406         return ret;
2407 }
2408 EXPORT_SYMBOL(lprocfs_oh_sum);
2409
2410 void lprocfs_oh_clear(struct obd_histogram *oh)
2411 {
2412         spin_lock(&oh->oh_lock);
2413         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
2414         spin_unlock(&oh->oh_lock);
2415 }
2416 EXPORT_SYMBOL(lprocfs_oh_clear);
2417
2418 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
2419                         int count, int *eof, void *data)
2420 {
2421         struct obd_device *obd = data;
2422         int c = 0;
2423
2424         if (obd == NULL)
2425                 return 0;
2426
2427         c += cfs_hash_debug_header(page, count);
2428         c += cfs_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2429         c += cfs_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2430         c += cfs_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2431
2432         return c;
2433 }
2434 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2435
2436 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2437                                    int count, int *eof, void *data)
2438 {
2439         struct obd_device *obd = data;
2440         int len = 0, size;
2441
2442         LASSERT(obd != NULL);
2443         LASSERT(count >= 0);
2444
2445         /* Set start of user data returned to
2446            page + off since the user may have
2447            requested to read much smaller than
2448            what we need to read */
2449         *start = page + off;
2450
2451         /* We know we are allocated a page here.
2452            Also we know that this function will
2453            not need to write more than a page
2454            so we can truncate at CFS_PAGE_SIZE.  */
2455         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
2456
2457         /* Initialize the page */
2458         memset(page, 0, size);
2459
2460         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2461                 goto out;
2462         if (obd->obd_max_recoverable_clients == 0) {
2463                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2464                         goto out;
2465
2466                 goto fclose;
2467         }
2468
2469         /* sampled unlocked, but really... */
2470         if (obd->obd_recovering == 0) {
2471                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2472                         goto out;
2473                 if (lprocfs_obd_snprintf(&page, size, &len,
2474                                          "recovery_start: %lu\n",
2475                                          obd->obd_recovery_start) <= 0)
2476                         goto out;
2477                 if (lprocfs_obd_snprintf(&page, size, &len,
2478                                          "recovery_duration: %lu\n",
2479                                          obd->obd_recovery_end -
2480                                          obd->obd_recovery_start) <= 0)
2481                         goto out;
2482                 /* Number of clients that have completed recovery */
2483                 if (lprocfs_obd_snprintf(&page, size, &len,
2484                                          "completed_clients: %d/%d\n",
2485                                          obd->obd_max_recoverable_clients -
2486                                          obd->obd_stale_clients,
2487                                          obd->obd_max_recoverable_clients) <= 0)
2488                         goto out;
2489                 if (lprocfs_obd_snprintf(&page, size, &len,
2490                                          "replayed_requests: %d\n",
2491                                          obd->obd_replayed_requests) <= 0)
2492                         goto out;
2493                 if (lprocfs_obd_snprintf(&page, size, &len,
2494                                          "last_transno: "LPD64"\n",
2495                                          obd->obd_next_recovery_transno - 1)<=0)
2496                         goto out;
2497                 if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
2498                                          obd->obd_version_recov ?
2499                                          "ENABLED" : "DISABLED") <=0)
2500                         goto out;
2501                 if (lprocfs_obd_snprintf(&page, size, &len, "IR: %s\n",
2502                                          obd->obd_no_ir ?
2503                                          "DISABLED" : "ENABLED") <= 0)
2504                         goto out;
2505                 goto fclose;
2506         }
2507
2508         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2509                 goto out;
2510         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2511                                  obd->obd_recovery_start) <= 0)
2512                 goto out;
2513         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2514                                  cfs_time_current_sec() >=
2515                                  obd->obd_recovery_start +
2516                                  obd->obd_recovery_timeout ? 0 :
2517                                  obd->obd_recovery_start +
2518                                  obd->obd_recovery_timeout -
2519                                  cfs_time_current_sec()) <= 0)
2520                 goto out;
2521         if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2522                                  cfs_atomic_read(&obd->obd_connected_clients),
2523                                  obd->obd_max_recoverable_clients) <= 0)
2524                 goto out;
2525         /* Number of clients that have completed recovery */
2526         if (lprocfs_obd_snprintf(&page, size, &len,"req_replay_clients: %d\n",
2527                                  cfs_atomic_read(&obd->obd_req_replay_clients))
2528                 <= 0)
2529                 goto out;
2530         if (lprocfs_obd_snprintf(&page, size, &len,"lock_repay_clients: %d\n",
2531                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2532                 <=0)
2533                 goto out;
2534         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d\n",
2535                                  cfs_atomic_read(&obd->obd_connected_clients) -
2536                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2537                 <=0)
2538                 goto out;
2539         if (lprocfs_obd_snprintf(&page, size, &len,"evicted_clients: %d\n",
2540                                  obd->obd_stale_clients) <= 0)
2541                 goto out;
2542         if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d\n",
2543                                  obd->obd_replayed_requests) <= 0)
2544                 goto out;
2545         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2546                                  obd->obd_requests_queued_for_recovery) <= 0)
2547                 goto out;
2548
2549         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2550                                  obd->obd_next_recovery_transno) <= 0)
2551                 goto out;
2552
2553 fclose:
2554         *eof = 1;
2555 out:
2556         return min(count, len - (int)off);
2557 }
2558 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2559
2560 int lprocfs_obd_rd_ir_factor(char *page, char **start, off_t off,
2561                              int count, int *eof, void *data)
2562 {
2563         struct obd_device *obd = (struct obd_device *)data;
2564         LASSERT(obd != NULL);
2565
2566         return snprintf(page, count, "%d\n",
2567                         obd->obd_recovery_ir_factor);
2568 }
2569 EXPORT_SYMBOL(lprocfs_obd_rd_ir_factor);
2570
2571 int lprocfs_obd_wr_ir_factor(struct file *file, const char *buffer,
2572                              unsigned long count, void *data)
2573 {
2574         struct obd_device *obd = (struct obd_device *)data;
2575         int val, rc;
2576         LASSERT(obd != NULL);
2577
2578         rc = lprocfs_write_helper(buffer, count, &val);
2579         if (rc)
2580                 return rc;
2581
2582         if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
2583                 return -EINVAL;
2584
2585         obd->obd_recovery_ir_factor = val;
2586         return count;
2587 }
2588 EXPORT_SYMBOL(lprocfs_obd_wr_ir_factor);
2589
2590 int lprocfs_obd_rd_recovery_time_soft(char *page, char **start, off_t off,
2591                                       int count, int *eof, void *data)
2592 {
2593         struct obd_device *obd = (struct obd_device *)data;
2594         LASSERT(obd != NULL);
2595
2596         return snprintf(page, count, "%d\n",
2597                         obd->obd_recovery_timeout);
2598 }
2599 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_soft);
2600
2601 int lprocfs_obd_wr_recovery_time_soft(struct file *file, const char *buffer,
2602                                       unsigned long count, void *data)
2603 {
2604         struct obd_device *obd = (struct obd_device *)data;
2605         int val, rc;
2606         LASSERT(obd != NULL);
2607
2608         rc = lprocfs_write_helper(buffer, count, &val);
2609         if (rc)
2610                 return rc;
2611
2612         obd->obd_recovery_timeout = val;
2613         return count;
2614 }
2615 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_soft);
2616
2617 int lprocfs_obd_rd_recovery_time_hard(char *page, char **start, off_t off,
2618                                       int count, int *eof, void *data)
2619 {
2620         struct obd_device *obd = data;
2621         LASSERT(obd != NULL);
2622
2623         return snprintf(page, count, "%u\n", obd->obd_recovery_time_hard);
2624 }
2625 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_hard);
2626
2627 int lprocfs_obd_wr_recovery_time_hard(struct file *file, const char *buffer,
2628                                       unsigned long count, void *data)
2629 {
2630         struct obd_device *obd = data;
2631         int val, rc;
2632         LASSERT(obd != NULL);
2633
2634         rc = lprocfs_write_helper(buffer, count, &val);
2635         if (rc)
2636                 return rc;
2637
2638         obd->obd_recovery_time_hard = val;
2639         return count;
2640 }
2641 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_hard);
2642
2643 int lprocfs_obd_rd_mntdev(char *page, char **start, off_t off,
2644                           int count, int *eof, void *data)
2645 {
2646         struct obd_device *obd = (struct obd_device *)data;
2647         struct lustre_mount_info *lmi;
2648         const char *dev_name;
2649
2650         LASSERT(obd != NULL);
2651         lmi = server_get_mount_2(obd->obd_name);
2652         dev_name = get_mntdev_name(lmi->lmi_sb);
2653         LASSERT(dev_name != NULL);
2654         *eof = 1;
2655         server_put_mount_2(obd->obd_name, lmi->lmi_mnt);
2656         return snprintf(page, count, "%s\n", dev_name);
2657 }
2658 EXPORT_SYMBOL(lprocfs_obd_rd_mntdev);
2659
2660 int lprocfs_obd_rd_max_pages_per_rpc(char *page, char **start, off_t off,
2661                                      int count, int *eof, void *data)
2662 {
2663         struct obd_device *dev = data;
2664         struct client_obd *cli = &dev->u.cli;
2665         int rc;
2666
2667         client_obd_list_lock(&cli->cl_loi_list_lock);
2668         rc = snprintf(page, count, "%d\n", cli->cl_max_pages_per_rpc);
2669         client_obd_list_unlock(&cli->cl_loi_list_lock);
2670         return rc;
2671 }
2672 EXPORT_SYMBOL(lprocfs_obd_rd_max_pages_per_rpc);
2673
2674 int lprocfs_target_rd_instance(char *page, char **start, off_t off,
2675                                int count, int *eof, void *data)
2676 {
2677         struct obd_device *obd = (struct obd_device *)data;
2678         struct obd_device_target *target = &obd->u.obt;
2679
2680         LASSERT(obd != NULL);
2681         LASSERT(target->obt_magic == OBT_MAGIC);
2682         *eof = 1;
2683         return snprintf(page, count, "%u\n", obd->u.obt.obt_instance);
2684 }
2685 EXPORT_SYMBOL(lprocfs_target_rd_instance);
2686 #endif /* LPROCFS*/