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