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