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