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