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