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