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