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