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