Whamcloud - gitweb
Branch HEAD
[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 /** add up per-cpu counters */
648 void lprocfs_stats_collect(struct lprocfs_stats *stats, int idx,
649                            struct lprocfs_counter *cnt)
650 {
651         unsigned int num_cpu;
652         struct lprocfs_counter t;
653         struct lprocfs_counter *percpu_cntr;
654         int centry, i;
655
656         memset(cnt, 0, sizeof(*cnt));
657
658         if (stats == NULL) {
659                 /* set count to 1 to avoid divide-by-zero errs in callers */
660                 cnt->lc_count = 1;
661                 return;
662         }
663
664         cnt->lc_min = LC_MIN_INIT;
665
666         if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
667                 num_cpu = 1;
668         else
669                 num_cpu = num_possible_cpus();
670
671         for (i = 0; i < num_cpu; i++) {
672                 percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[idx];
673
674                 do {
675                         centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
676                         t.lc_count = percpu_cntr->lc_count;
677                         t.lc_sum = percpu_cntr->lc_sum;
678                         t.lc_min = percpu_cntr->lc_min;
679                         t.lc_max = percpu_cntr->lc_max;
680                         t.lc_sumsquare = percpu_cntr->lc_sumsquare;
681                 } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
682                          centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
683                 cnt->lc_count += t.lc_count;
684                 cnt->lc_sum += t.lc_sum;
685                 if (t.lc_min < cnt->lc_min)
686                         cnt->lc_min = t.lc_min;
687                 if (t.lc_max > cnt->lc_max)
688                         cnt->lc_max = t.lc_max;
689                 cnt->lc_sumsquare += t.lc_sumsquare;
690         }
691
692         cnt->lc_units = stats->ls_percpu[0]->lp_cntr[idx].lc_units;
693 }
694
695 /**
696  * Append a space separated list of current set flags to str.
697  */
698 #define flag2str(flag) \
699         if (imp->imp_##flag && max - len > 0) \
700              len += snprintf(str + len, max - len, "%s" #flag, len ? ", " : "");
701 static int obd_import_flags2str(struct obd_import *imp, char *str, int max)
702 {
703         int len = 0;
704
705         if (imp->imp_obd->obd_no_recov)
706                 len += snprintf(str, max - len, "no_recov");
707
708         flag2str(invalid);
709         flag2str(deactive);
710         flag2str(replayable);
711         flag2str(pingable);
712         flag2str(recon_bk);
713         flag2str(last_recon);
714         return len;
715 }
716 #undef flags2str
717
718 static const char *obd_connect_names[] = {
719         "read_only",
720         "lov_index",
721         "unused",
722         "write_grant",
723         "server_lock",
724         "version",
725         "request_portal",
726         "acl",
727         "xattr",
728         "create_on_write",
729         "truncate_lock",
730         "initial_transno",
731         "inode_bit_locks",
732         "join_file",
733         "getattr_by_fid",
734         "no_oh_for_devices",
735         "local_client",
736         "remote_client",
737         "max_byte_per_rpc",
738         "64bit_qdata",
739         "mds_capability",
740         "oss_capability",
741         "early_lock_cancel",
742         "som",
743         "adaptive_timeouts",
744         "lru_resize",
745         "mds_mds_connection",
746         "real_conn",
747         "change_qunit_size",
748         "alt_checksum_algorithm",
749         "fid_is_enabled",
750         "version_recovery",
751         "pools",
752         "grant_shrink",
753         "skip_orphan",
754         NULL
755 };
756
757 static int obd_connect_flags2str(char *page, int count, __u64 flags, char *sep)
758 {
759         __u64 mask = 1;
760         int i, ret = 0;
761
762         for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
763                 if (flags & mask)
764                         ret += snprintf(page + ret, count - ret, "%s%s",
765                                         ret ? sep : "", obd_connect_names[i]);
766         }
767         if (flags & ~(mask - 1))
768                 ret += snprintf(page + ret, count - ret,
769                                 "%sunknown flags "LPX64,
770                                 ret ? sep : "", flags & ~(mask - 1));
771         return ret;
772 }
773
774 int lprocfs_rd_import(char *page, char **start, off_t off, int count,
775                       int *eof, void *data)
776 {
777         struct lprocfs_counter ret;
778         struct obd_device *obd = (struct obd_device *)data;
779         struct obd_import *imp;
780         int i, j, k, rw = 0;
781
782         LASSERT(obd != NULL);
783         LPROCFS_CLIMP_CHECK(obd);
784         imp = obd->u.cli.cl_import;
785         *eof = 1;
786
787         i = snprintf(page, count,
788                      "import:\n"
789                      "    name: %s\n"
790                      "    target: %s\n"
791                      "    current_connection: %s\n"
792                      "    state: %s\n"
793                      "    connect_flags: [",
794                      obd->obd_name,
795                      obd2cli_tgt(obd),
796                      imp->imp_connection->c_remote_uuid.uuid,
797                      ptlrpc_import_state_name(imp->imp_state));
798         i += obd_connect_flags2str(page + i, count - i,
799                                    imp->imp_connect_data.ocd_connect_flags,
800                                    ", ");
801         i += snprintf(page + i, count - i,
802                       "]\n"
803                       "    import_flags: [");
804         i += obd_import_flags2str(imp, page + i, count - i);
805
806         i += snprintf(page + i, count - i,
807                       "]\n"
808                       "    connection:\n"
809                       "       connection_attempts: %u\n"
810                       "       generation: %u\n"
811                       "       in-progress_invalidations: %u\n",
812                       imp->imp_conn_cnt,
813                       imp->imp_generation,
814                       atomic_read(&imp->imp_inval_count));
815
816         lprocfs_stats_collect(obd->obd_svc_stats, PTLRPC_REQWAIT_CNTR, &ret);
817         do_div(ret.lc_sum, ret.lc_count);
818         i += snprintf(page + i, count - i,
819                       "    rpcs:\n"
820                       "       inflight: %u\n"
821                       "       unregistering: %u\n"
822                       "       timeouts: %u\n"
823                       "       avg_waittime: "LPU64" %s\n",
824                       atomic_read(&imp->imp_inflight),
825                       atomic_read(&imp->imp_unregistering),
826                       atomic_read(&imp->imp_timeouts),
827                       ret.lc_sum, ret.lc_units);
828
829         k = 0;
830         for(j = 0; j < IMP_AT_MAX_PORTALS; j++) {
831                 if (imp->imp_at.iat_portal[j] == 0)
832                         break;
833                 k = max_t(unsigned int, k,
834                           at_get(&imp->imp_at.iat_service_estimate[j]));
835         }
836         i += snprintf(page + i, count - i,
837                       "    service_estimates:\n"
838                       "       services: %u sec\n"
839                       "       network: %u sec\n",
840                       k,
841                       at_get(&imp->imp_at.iat_net_latency));
842
843         i += snprintf(page + i, count - i,
844                       "    transactions:\n"
845                       "       last_replay: "LPU64"\n"
846                       "       peer_committed: "LPU64"\n"
847                       "       last_checked: "LPU64"\n",
848                       imp->imp_last_replay_transno,
849                       imp->imp_peer_committed_transno,
850                       imp->imp_last_transno_checked);
851
852         /* avg data rates */
853         for (rw = 0; rw <= 1; rw++) {
854                 lprocfs_stats_collect(obd->obd_svc_stats,
855                                       PTLRPC_LAST_CNTR + BRW_READ_BYTES + rw,
856                                       &ret);
857                 if (ret.lc_sum > 0) {
858                         do_div(ret.lc_sum, ret.lc_count);
859                         i += snprintf(page + i, count - i,
860                                       "    %s_data_averages:\n"
861                                       "       bytes_per_rpc: "LPU64"\n",
862                                       rw ? "write" : "read",
863                                       ret.lc_sum);
864                 }
865                 k = (int)ret.lc_sum;
866                 j = opcode_offset(OST_READ + rw) + EXTRA_MAX_OPCODES;
867                 lprocfs_stats_collect(obd->obd_svc_stats, j, &ret);
868                 if (ret.lc_sum > 0) {
869                         do_div(ret.lc_sum, ret.lc_count);
870                         i += snprintf(page + i, count - i,
871                                       "       %s_per_rpc: "LPU64"\n",
872                                       ret.lc_units, ret.lc_sum);
873                         j = (int)ret.lc_sum;
874                         if (j > 0)
875                                 i += snprintf(page + i, count - i,
876                                               "       MB_per_sec: %u.%.02u\n",
877                                               k / j, (100 * k / j) % 100);
878                 }
879         }
880
881         LPROCFS_CLIMP_EXIT(obd);
882         return i;
883 }
884
885 int lprocfs_rd_state(char *page, char **start, off_t off, int count,
886                       int *eof, void *data)
887 {
888         struct obd_device *obd = (struct obd_device *)data;
889         struct obd_import *imp;
890         int i, j, k;
891
892         LASSERT(obd != NULL);
893         LPROCFS_CLIMP_CHECK(obd);
894         imp = obd->u.cli.cl_import;
895         *eof = 1;
896
897         i = snprintf(page, count, "current_state: %s\n",
898                      ptlrpc_import_state_name(imp->imp_state));
899         i += snprintf(page + i, count - i,
900                       "state_history:\n");
901         k = imp->imp_state_hist_idx;
902         for (j = 0; j < IMP_STATE_HIST_LEN; j++) {
903                 struct import_state_hist *ish =
904                         &imp->imp_state_hist[(k + j) % IMP_STATE_HIST_LEN];
905                 if (ish->ish_state == 0)
906                         continue;
907                 i += snprintf(page + i, count - i, " - ["CFS_TIME_T", %s]\n",
908                               ish->ish_time,
909                               ptlrpc_import_state_name(ish->ish_state));
910         }
911
912         LPROCFS_CLIMP_EXIT(obd);
913         return i;
914 }
915
916 int lprocfs_at_hist_helper(char *page, int count, int rc,
917                            struct adaptive_timeout *at)
918 {
919         int i;
920         for (i = 0; i < AT_BINS; i++)
921                 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
922         rc += snprintf(page + rc, count - rc, "\n");
923         return rc;
924 }
925
926 int lprocfs_rd_quota_resend_count(char *page, char **start, off_t off,
927                                   int count, int *eof, void *data)
928 {
929         struct obd_device *obd = data;
930
931         return snprintf(page, count, "%u\n",
932                         atomic_read(&obd->u.cli.cl_quota_resends));
933 }
934
935 int lprocfs_wr_quota_resend_count(struct file *file, const char *buffer,
936                                   unsigned long count, void *data)
937 {
938         struct obd_device *obd = data;
939         int val, rc;
940
941         rc = lprocfs_write_helper(buffer, count, &val);
942         if (rc)
943                 return rc;
944
945         if (val < 0)
946                return -EINVAL;
947
948         atomic_set(&obd->u.cli.cl_quota_resends, val);
949
950         return count;
951 }
952
953 /* See also ptlrpc_lprocfs_rd_timeouts */
954 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
955                         int *eof, void *data)
956 {
957         struct obd_device *obd = (struct obd_device *)data;
958         struct obd_import *imp;
959         unsigned int cur, worst;
960         time_t now, worstt;
961         struct dhms ts;
962         int i, rc = 0;
963
964         LASSERT(obd != NULL);
965         LPROCFS_CLIMP_CHECK(obd);
966         imp = obd->u.cli.cl_import;
967         *eof = 1;
968
969         now = cfs_time_current_sec();
970
971         /* Some network health info for kicks */
972         s2dhms(&ts, now - imp->imp_last_reply_time);
973         rc += snprintf(page + rc, count - rc,
974                        "%-10s : %ld, "DHMS_FMT" ago\n",
975                        "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
976
977         cur = at_get(&imp->imp_at.iat_net_latency);
978         worst = imp->imp_at.iat_net_latency.at_worst_ever;
979         worstt = imp->imp_at.iat_net_latency.at_worst_time;
980         s2dhms(&ts, now - worstt);
981         rc += snprintf(page + rc, count - rc,
982                        "%-10s : cur %3u  worst %3u (at %ld, "DHMS_FMT" ago) ",
983                        "network", cur, worst, worstt, DHMS_VARS(&ts));
984         rc = lprocfs_at_hist_helper(page, count, rc,
985                                     &imp->imp_at.iat_net_latency);
986
987         for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
988                 if (imp->imp_at.iat_portal[i] == 0)
989                         break;
990                 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
991                 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
992                 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
993                 s2dhms(&ts, now - worstt);
994                 rc += snprintf(page + rc, count - rc,
995                                "portal %-2d  : cur %3u  worst %3u (at %ld, "
996                                DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
997                                cur, worst, worstt, DHMS_VARS(&ts));
998                 rc = lprocfs_at_hist_helper(page, count, rc,
999                                           &imp->imp_at.iat_service_estimate[i]);
1000         }
1001
1002         LPROCFS_CLIMP_EXIT(obd);
1003         return rc;
1004 }
1005
1006 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
1007                              int count, int *eof, void *data)
1008 {
1009         struct obd_device *obd = data;
1010         __u64 flags;
1011         int ret = 0;
1012
1013         LPROCFS_CLIMP_CHECK(obd);
1014         flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
1015         ret = snprintf(page, count, "flags="LPX64"\n", flags);
1016         ret += obd_connect_flags2str(page + ret, count - ret, flags, "\n");
1017         ret += snprintf(page + ret, count - ret, "\n");
1018         LPROCFS_CLIMP_EXIT(obd);
1019         return ret;
1020 }
1021 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
1022
1023 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
1024                            int *eof,  void *data)
1025 {
1026         struct obd_device *obd = data;
1027
1028         LASSERT(obd != NULL);
1029         *eof = 1;
1030         return snprintf(page, count, "%u\n", obd->obd_num_exports);
1031 }
1032
1033 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
1034                        int *eof, void *data)
1035 {
1036         struct obd_type *class = (struct obd_type*) data;
1037
1038         LASSERT(class != NULL);
1039         *eof = 1;
1040         return snprintf(page, count, "%d\n", class->typ_refcnt);
1041 }
1042
1043 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
1044 {
1045         int rc = 0;
1046
1047         LASSERT(obd != NULL);
1048         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
1049         LASSERT(obd->obd_type->typ_procroot != NULL);
1050
1051         obd->obd_proc_entry = lprocfs_register(obd->obd_name,
1052                                                obd->obd_type->typ_procroot,
1053                                                list, obd);
1054         if (IS_ERR(obd->obd_proc_entry)) {
1055                 rc = PTR_ERR(obd->obd_proc_entry);
1056                 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
1057                 obd->obd_proc_entry = NULL;
1058         }
1059         return rc;
1060 }
1061
1062 int lprocfs_obd_cleanup(struct obd_device *obd)
1063 {
1064         if (!obd)
1065                 return -EINVAL;
1066         if (obd->obd_proc_exports_entry) {
1067                 /* Should be no exports left */
1068                 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
1069                 lprocfs_remove(&obd->obd_proc_exports_entry);
1070                 obd->obd_proc_exports_entry = NULL;
1071         }
1072         if (obd->obd_proc_entry) {
1073                 lprocfs_remove(&obd->obd_proc_entry);
1074                 obd->obd_proc_entry = NULL;
1075         }
1076         return 0;
1077 }
1078
1079 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
1080 {
1081         CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
1082                client_stat->nid_proc, client_stat->nid_stats,
1083                client_stat->nid_brw_stats);
1084
1085         LASSERTF(atomic_read(&client_stat->nid_exp_ref_count) == 0,
1086                  "count %d\n", atomic_read(&client_stat->nid_exp_ref_count));
1087
1088         hlist_del_init(&client_stat->nid_hash);
1089
1090         if (client_stat->nid_proc)
1091                 lprocfs_remove(&client_stat->nid_proc);
1092
1093         if (client_stat->nid_stats)
1094                 lprocfs_free_stats(&client_stat->nid_stats);
1095
1096         if (client_stat->nid_brw_stats)
1097                 OBD_FREE_PTR(client_stat->nid_brw_stats);
1098
1099         if (client_stat->nid_ldlm_stats)
1100                 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
1101
1102         OBD_FREE_PTR(client_stat);
1103         return;
1104
1105 }
1106
1107 void lprocfs_free_per_client_stats(struct obd_device *obd)
1108 {
1109         struct nid_stat *stat;
1110         ENTRY;
1111
1112         /* we need extra list - because hash_exit called to early */
1113         /* not need locking because all clients is died */
1114         while(!list_empty(&obd->obd_nid_stats)) {
1115                 stat = list_entry(obd->obd_nid_stats.next,
1116                                   struct nid_stat, nid_list);
1117                 list_del_init(&stat->nid_list);
1118                 lprocfs_free_client_stats(stat);
1119         }
1120
1121         EXIT;
1122 }
1123
1124 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
1125                                           enum lprocfs_stats_flags flags)
1126 {
1127         struct lprocfs_stats *stats;
1128         unsigned int percpusize;
1129         unsigned int i, j;
1130         unsigned int num_cpu;
1131
1132         if (num == 0)
1133                 return NULL;
1134
1135         if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
1136                 num_cpu = 1;
1137         else
1138                 num_cpu = num_possible_cpus();
1139
1140         OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
1141         if (stats == NULL)
1142                 return NULL;
1143
1144         if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
1145                 stats->ls_flags = flags;
1146                 spin_lock_init(&stats->ls_lock);
1147                 /* Use this lock only if there are no percpu areas */
1148         } else {
1149                 stats->ls_flags = 0;
1150         }
1151
1152         percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
1153         if (num_cpu > 1)
1154                 percpusize = L1_CACHE_ALIGN(percpusize);
1155
1156         for (i = 0; i < num_cpu; i++) {
1157                 OBD_ALLOC(stats->ls_percpu[i], percpusize);
1158                 if (stats->ls_percpu[i] == NULL) {
1159                         for (j = 0; j < i; j++) {
1160                                 OBD_FREE(stats->ls_percpu[j], percpusize);
1161                                 stats->ls_percpu[j] = NULL;
1162                         }
1163                         break;
1164                 }
1165         }
1166         if (stats->ls_percpu[0] == NULL) {
1167                 OBD_FREE(stats, offsetof(typeof(*stats),
1168                                          ls_percpu[num_cpu]));
1169                 return NULL;
1170         }
1171
1172         stats->ls_num = num;
1173         return stats;
1174 }
1175
1176 void lprocfs_free_stats(struct lprocfs_stats **statsh)
1177 {
1178         struct lprocfs_stats *stats = *statsh;
1179         unsigned int num_cpu;
1180         unsigned int percpusize;
1181         unsigned int i;
1182
1183         if (stats == NULL || stats->ls_num == 0)
1184                 return;
1185         *statsh = NULL;
1186
1187         if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1188                 num_cpu = 1;
1189         else
1190                 num_cpu = num_possible_cpus();
1191
1192         percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
1193         if (num_cpu > 1)
1194                 percpusize = L1_CACHE_ALIGN(percpusize);
1195         for (i = 0; i < num_cpu; i++)
1196                 OBD_FREE(stats->ls_percpu[i], percpusize);
1197         OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
1198 }
1199
1200 void lprocfs_clear_stats(struct lprocfs_stats *stats)
1201 {
1202         struct lprocfs_counter *percpu_cntr;
1203         int i,j;
1204         unsigned int num_cpu;
1205
1206         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1207
1208         for (i = 0; i < num_cpu; i++) {
1209                 for (j = 0; j < stats->ls_num; j++) {
1210                         percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
1211                         atomic_inc(&percpu_cntr->lc_cntl.la_entry);
1212                         percpu_cntr->lc_count = 0;
1213                         percpu_cntr->lc_sum = 0;
1214                         percpu_cntr->lc_min = LC_MIN_INIT;
1215                         percpu_cntr->lc_max = 0;
1216                         percpu_cntr->lc_sumsquare = 0;
1217                         atomic_inc(&percpu_cntr->lc_cntl.la_exit);
1218                 }
1219         }
1220
1221         lprocfs_stats_unlock(stats);
1222 }
1223
1224 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
1225                                        size_t len, loff_t *off)
1226 {
1227         struct seq_file *seq = file->private_data;
1228         struct lprocfs_stats *stats = seq->private;
1229
1230         lprocfs_clear_stats(stats);
1231
1232         return len;
1233 }
1234
1235 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
1236 {
1237         struct lprocfs_stats *stats = p->private;
1238         /* return 1st cpu location */
1239         return (*pos >= stats->ls_num) ? NULL :
1240                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1241 }
1242
1243 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1244 {
1245 }
1246
1247 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1248 {
1249         struct lprocfs_stats *stats = p->private;
1250         ++*pos;
1251         return (*pos >= stats->ls_num) ? NULL :
1252                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1253 }
1254
1255 /* seq file export of one lprocfs counter */
1256 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1257 {
1258        struct lprocfs_stats *stats = p->private;
1259        struct lprocfs_counter *cntr = v;
1260        struct lprocfs_counter ret;
1261        int idx, rc = 0;
1262
1263        if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
1264                struct timeval now;
1265                do_gettimeofday(&now);
1266                rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1267                                "snapshot_time", now.tv_sec, now.tv_usec);
1268                if (rc < 0)
1269                        return rc;
1270        }
1271        idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
1272
1273        lprocfs_stats_collect(stats, idx, &ret);
1274
1275        if (ret.lc_count == 0)
1276                goto out;
1277
1278        rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
1279                        ret.lc_count, cntr->lc_units);
1280
1281        if (rc < 0)
1282                goto out;
1283
1284        if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
1285                rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1286                                ret.lc_min, ret.lc_max, ret.lc_sum);
1287                if (rc < 0)
1288                        goto out;
1289                if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
1290                        rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1291                if (rc < 0)
1292                        goto out;
1293        }
1294        rc = seq_printf(p, "\n");
1295  out:
1296        return (rc < 0) ? rc : 0;
1297 }
1298
1299 struct seq_operations lprocfs_stats_seq_sops = {
1300         start: lprocfs_stats_seq_start,
1301         stop:  lprocfs_stats_seq_stop,
1302         next:  lprocfs_stats_seq_next,
1303         show:  lprocfs_stats_seq_show,
1304 };
1305
1306 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1307 {
1308         struct proc_dir_entry *dp = PDE(inode);
1309         struct seq_file *seq;
1310         int rc;
1311
1312         LPROCFS_ENTRY_AND_CHECK(dp);
1313         rc = seq_open(file, &lprocfs_stats_seq_sops);
1314         if (rc) {
1315                 LPROCFS_EXIT();
1316                 return rc;
1317         }
1318         seq = file->private_data;
1319         seq->private = dp->data;
1320         return 0;
1321 }
1322
1323 struct file_operations lprocfs_stats_seq_fops = {
1324         .owner   = THIS_MODULE,
1325         .open    = lprocfs_stats_seq_open,
1326         .read    = seq_read,
1327         .write   = lprocfs_stats_seq_write,
1328         .llseek  = seq_lseek,
1329         .release = lprocfs_seq_release,
1330 };
1331
1332 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1333                            struct lprocfs_stats *stats)
1334 {
1335         struct proc_dir_entry *entry;
1336         LASSERT(root != NULL);
1337
1338         entry = create_proc_entry(name, 0644, root);
1339         if (entry == NULL)
1340                 return -ENOMEM;
1341         entry->proc_fops = &lprocfs_stats_seq_fops;
1342         entry->data = stats;
1343         return 0;
1344 }
1345
1346 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1347                           unsigned conf, const char *name, const char *units)
1348 {
1349         struct lprocfs_counter *c;
1350         int i;
1351         unsigned int num_cpu;
1352
1353         LASSERT(stats != NULL);
1354
1355         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1356
1357         for (i = 0; i < num_cpu; i++) {
1358                 c = &(stats->ls_percpu[i]->lp_cntr[index]);
1359                 c->lc_config = conf;
1360                 c->lc_count = 0;
1361                 c->lc_sum = 0;
1362                 c->lc_min = LC_MIN_INIT;
1363                 c->lc_max = 0;
1364                 c->lc_name = name;
1365                 c->lc_units = units;
1366         }
1367
1368         lprocfs_stats_unlock(stats);
1369 }
1370 EXPORT_SYMBOL(lprocfs_counter_init);
1371
1372 #define LPROCFS_OBD_OP_INIT(base, stats, op)                               \
1373 do {                                                                       \
1374         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);              \
1375         LASSERT(coffset < stats->ls_num);                                  \
1376         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");              \
1377 } while (0)
1378
1379 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1380 {
1381         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1382         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1383         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1384         LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1385         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1386         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1387         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1388         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1389         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1390         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1391         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1392         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1393         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1394         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1395         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1396         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1397         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1398         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1399         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1400         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1401         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1402         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1403         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1404         LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
1405         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1406         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1407         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1408         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create_async);
1409         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1410         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1411         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1412         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1413         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1414         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1415         LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1416         LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1417         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1418         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1419         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1420         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1421         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1422         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1423         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1424         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1425         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1426         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1427         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1428         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1429         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1430         LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1431         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1432         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1433         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1434         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1435         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1436         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1437         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1438         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1439         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
1440         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1441         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1442         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quota_adjust_qunit);
1443         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1444         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1445         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1446         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1447         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1448         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
1449         LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
1450 }
1451
1452 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1453 {
1454         struct lprocfs_stats *stats;
1455         unsigned int num_stats;
1456         int rc, i;
1457
1458         LASSERT(obd->obd_stats == NULL);
1459         LASSERT(obd->obd_proc_entry != NULL);
1460         LASSERT(obd->obd_cntr_base == 0);
1461
1462         num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1463                 num_private_stats - 1 /* o_owner */;
1464         stats = lprocfs_alloc_stats(num_stats, 0);
1465         if (stats == NULL)
1466                 return -ENOMEM;
1467
1468         lprocfs_init_ops_stats(num_private_stats, stats);
1469
1470         for (i = num_private_stats; i < num_stats; i++) {
1471                 /* If this LBUGs, it is likely that an obd
1472                  * operation was added to struct obd_ops in
1473                  * <obd.h>, and that the corresponding line item
1474                  * LPROCFS_OBD_OP_INIT(.., .., opname)
1475                  * is missing from the list above. */
1476                 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1477                          "Missing obd_stat initializer obd_op "
1478                          "operation at offset %d.\n", i - num_private_stats);
1479         }
1480         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1481         if (rc < 0) {
1482                 lprocfs_free_stats(&stats);
1483         } else {
1484                 obd->obd_stats  = stats;
1485                 obd->obd_cntr_base = num_private_stats;
1486         }
1487         return rc;
1488 }
1489
1490 void lprocfs_free_obd_stats(struct obd_device *obd)
1491 {
1492         if (obd->obd_stats)
1493                 lprocfs_free_stats(&obd->obd_stats);
1494 }
1495
1496 #define LPROCFS_MD_OP_INIT(base, stats, op)                             \
1497 do {                                                                    \
1498         unsigned int coffset = base + MD_COUNTER_OFFSET(op);            \
1499         LASSERT(coffset < stats->ls_num);                               \
1500         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
1501 } while (0)
1502
1503 int lprocfs_alloc_md_stats(struct obd_device *obd,
1504                            unsigned num_private_stats)
1505 {
1506         struct lprocfs_stats *stats;
1507         unsigned int num_stats;
1508         int rc, i;
1509
1510         LASSERT(obd->md_stats == NULL);
1511         LASSERT(obd->obd_proc_entry != NULL);
1512         LASSERT(obd->md_cntr_base == 0);
1513
1514         num_stats = 1 + MD_COUNTER_OFFSET(revalidate_lock) +
1515                     num_private_stats;
1516         stats = lprocfs_alloc_stats(num_stats, 0);
1517         if (stats == NULL)
1518                 return -ENOMEM;
1519
1520         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1521         LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1522         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1523         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1524         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1525         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1526         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1527         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1528         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1529         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1530         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1531         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1532         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1533         LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1534         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1535         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1536         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1537         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1538         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1539         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1540         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1541         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1542         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1543         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1544         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1545         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1546         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1547         LPROCFS_MD_OP_INIT(num_private_stats, stats, unpack_capa);
1548         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1549         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1550         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1551
1552         for (i = num_private_stats; i < num_stats; i++) {
1553                 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1554                         CERROR("Missing md_stat initializer md_op "
1555                                "operation at offset %d. Aborting.\n",
1556                                i - num_private_stats);
1557                         LBUG();
1558                 }
1559         }
1560         rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
1561         if (rc < 0) {
1562                 lprocfs_free_stats(&stats);
1563         } else {
1564                 obd->md_stats  = stats;
1565                 obd->md_cntr_base = num_private_stats;
1566         }
1567         return rc;
1568 }
1569
1570 void lprocfs_free_md_stats(struct obd_device *obd)
1571 {
1572         struct lprocfs_stats *stats = obd->md_stats;
1573
1574         if (stats != NULL) {
1575                 obd->md_stats = NULL;
1576                 obd->md_cntr_base = 0;
1577                 lprocfs_free_stats(&stats);
1578         }
1579 }
1580
1581 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1582 {
1583         lprocfs_counter_init(ldlm_stats,
1584                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
1585                              0, "ldlm_enqueue", "reqs");
1586         lprocfs_counter_init(ldlm_stats,
1587                              LDLM_CONVERT - LDLM_FIRST_OPC,
1588                              0, "ldlm_convert", "reqs");
1589         lprocfs_counter_init(ldlm_stats,
1590                              LDLM_CANCEL - LDLM_FIRST_OPC,
1591                              0, "ldlm_cancel", "reqs");
1592         lprocfs_counter_init(ldlm_stats,
1593                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1594                              0, "ldlm_bl_callback", "reqs");
1595         lprocfs_counter_init(ldlm_stats,
1596                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1597                              0, "ldlm_cp_callback", "reqs");
1598         lprocfs_counter_init(ldlm_stats,
1599                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1600                              0, "ldlm_gl_callback", "reqs");
1601 }
1602
1603 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1604                          int *eof,  void *data)
1605 {
1606         struct obd_export *exp = data;
1607         LASSERT(exp != NULL);
1608         *eof = 1;
1609         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1610 }
1611
1612 struct exp_uuid_cb_data {
1613         char                   *page;
1614         int                     count;
1615         int                    *eof;
1616         int                    *len;
1617 };
1618
1619 static void
1620 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1621                             int count, int *eof, int *len)
1622 {
1623         cb_data->page = page;
1624         cb_data->count = count;
1625         cb_data->eof = eof;
1626         cb_data->len = len;
1627 }
1628
1629 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1630 {
1631         struct obd_export *exp = (struct obd_export *)obj;
1632         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1633
1634         if (exp->exp_nid_stats)
1635                 *data->len += snprintf((data->page + *data->len),
1636                                        data->count, "%s\n",
1637                                        obd_uuid2str(&exp->exp_client_uuid));
1638 }
1639
1640 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1641                         int *eof,  void *data)
1642 {
1643         struct nid_stat *stats = (struct nid_stat *)data;
1644         struct exp_uuid_cb_data cb_data;
1645         struct obd_device *obd = stats->nid_obd;
1646         int len = 0;
1647
1648         *eof = 1;
1649         page[0] = '\0';
1650         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1651         lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1652                                  lprocfs_exp_print_uuid, &cb_data);
1653         return (*cb_data.len);
1654 }
1655
1656 void lprocfs_exp_print_hash(void *obj, void *cb_data)
1657 {
1658         struct exp_uuid_cb_data *data = cb_data;
1659         struct obd_export       *exp = obj;
1660         lustre_hash_t           *lh;
1661
1662         lh = exp->exp_lock_hash;
1663         if (lh) {
1664                 if (!*data->len)
1665                         *data->len += lustre_hash_debug_header(data->page,
1666                                                                data->count);
1667
1668                 *data->len += lustre_hash_debug_str(lh, data->page + *data->len,
1669                                                     data->count);
1670         }
1671 }
1672
1673 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1674                         int *eof,  void *data)
1675 {
1676         struct nid_stat *stats = (struct nid_stat *)data;
1677         struct exp_uuid_cb_data cb_data;
1678         struct obd_device *obd = stats->nid_obd;
1679         int len = 0;
1680
1681         *eof = 1;
1682         page[0] = '\0';
1683         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1684
1685         lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1686                                  lprocfs_exp_print_hash, &cb_data);
1687         return (*cb_data.len);
1688 }
1689
1690 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1691                                         int count, int *eof,  void *data)
1692 {
1693         *eof = 1;
1694         return snprintf(page, count, "%s\n",
1695                         "Write into this file to clear all nid stats and "
1696                         "stale nid entries");
1697 }
1698 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1699
1700 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1701 {
1702         struct nid_stat *stat = obj;
1703         int i;
1704         ENTRY;
1705         /* object has only hash + iterate_all references.
1706          * add/delete blocked by hash bucket lock */
1707         CDEBUG(D_INFO,"refcnt %d\n", atomic_read(&stat->nid_exp_ref_count));
1708         if (atomic_read(&stat->nid_exp_ref_count) == 2) {
1709                 hlist_del_init(&stat->nid_hash);
1710                 nidstat_putref(stat);
1711                 spin_lock(&stat->nid_obd->obd_nid_lock);
1712                 list_move(&stat->nid_list, data);
1713                 spin_unlock(&stat->nid_obd->obd_nid_lock);
1714                 EXIT;
1715                 return;
1716         }
1717         /* we has reference to object - only clear data*/
1718         if (stat->nid_stats)
1719                 lprocfs_clear_stats(stat->nid_stats);
1720
1721         if (stat->nid_brw_stats) {
1722                 for (i = 0; i < BRW_LAST; i++)
1723                         lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1724         }
1725         EXIT;
1726         return;
1727 }
1728
1729 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1730                                          unsigned long count, void *data)
1731 {
1732         struct obd_device *obd = (struct obd_device *)data;
1733         struct nid_stat *client_stat;
1734         CFS_LIST_HEAD(free_list);
1735
1736         lustre_hash_for_each(obd->obd_nid_stats_hash,
1737                              lprocfs_nid_stats_clear_write_cb, &free_list);
1738
1739         while (!list_empty(&free_list)) {
1740                 client_stat = list_entry(free_list.next, struct nid_stat,
1741                                          nid_list);
1742                 list_del_init(&client_stat->nid_list);
1743                 lprocfs_free_client_stats(client_stat);
1744         }
1745
1746         return count;
1747 }
1748 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1749
1750 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1751 {
1752         struct nid_stat *new_stat, *old_stat;
1753         struct obd_device *obd = NULL;
1754         cfs_proc_dir_entry_t *entry;
1755         int rc = 0;
1756         ENTRY;
1757
1758         *newnid = 0;
1759
1760         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1761             !exp->exp_obd->obd_nid_stats_hash)
1762                 RETURN(-EINVAL);
1763
1764         /* not test against zero because eric say:
1765          * You may only test nid against another nid, or LNET_NID_ANY.
1766          * Anything else is nonsense.*/
1767         if (!nid || *nid == LNET_NID_ANY)
1768                 RETURN(0);
1769
1770         obd = exp->exp_obd;
1771
1772         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1773
1774         OBD_ALLOC_PTR(new_stat);
1775         if (new_stat == NULL)
1776                 RETURN(-ENOMEM);
1777
1778         new_stat->nid               = *nid;
1779         new_stat->nid_obd           = exp->exp_obd;
1780         atomic_set(&new_stat->nid_exp_ref_count, 0);
1781
1782         old_stat = lustre_hash_findadd_unique(obd->obd_nid_stats_hash,
1783                                               nid, &new_stat->nid_hash);
1784         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1785                old_stat, libcfs_nid2str(*nid),
1786                atomic_read(&new_stat->nid_exp_ref_count));
1787
1788         /* Return -EALREADY here so that we know that the /proc
1789          * entry already has been created */
1790         if (old_stat != new_stat) {
1791                 spin_lock(&obd->obd_nid_lock);
1792                 if (exp->exp_nid_stats != old_stat) {
1793                         if (exp->exp_nid_stats)
1794                                 nidstat_putref(exp->exp_nid_stats);
1795                         exp->exp_nid_stats = old_stat;
1796                 } else {
1797                         /* lustre_hash_findadd_unique() has added
1798                          * old_stat's refcount */
1799                         nidstat_putref(old_stat);
1800                 }
1801
1802                 spin_unlock(&obd->obd_nid_lock);
1803
1804                 GOTO(destroy_new, rc = -EALREADY);
1805         }
1806         /* not found - create */
1807         new_stat->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1808                                               obd->obd_proc_exports_entry,
1809                                               NULL, NULL);
1810         if (new_stat->nid_proc == NULL) {
1811                 CERROR("Error making export directory for nid %s\n",
1812                        libcfs_nid2str(*nid));
1813                 GOTO(destroy_new_ns, rc = -ENOMEM);
1814         }
1815
1816         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
1817                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
1818         if (IS_ERR(entry)) {
1819                 CWARN("Error adding the NID stats file\n");
1820                 rc = PTR_ERR(entry);
1821                 GOTO(destroy_new_ns, rc);
1822         }
1823
1824         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
1825                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
1826         if (IS_ERR(entry)) {
1827                 CWARN("Error adding the hash file\n");
1828                 rc = PTR_ERR(entry);
1829                 GOTO(destroy_new_ns, rc);
1830         }
1831
1832         if (exp->exp_nid_stats)
1833                 nidstat_putref(exp->exp_nid_stats);
1834         nidstat_getref(new_stat);
1835         exp->exp_nid_stats = new_stat;
1836         *newnid = 1;
1837         /* protect competitive add to list, not need locking on destroy */
1838         spin_lock(&obd->obd_nid_lock);
1839         list_add(&new_stat->nid_list, &obd->obd_nid_stats);
1840         spin_unlock(&obd->obd_nid_lock);
1841
1842         RETURN(rc);
1843
1844 destroy_new_ns:
1845         if (new_stat->nid_proc != NULL)
1846                 lprocfs_remove(&new_stat->nid_proc);
1847         lustre_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
1848
1849 destroy_new:
1850         OBD_FREE_PTR(new_stat);
1851         RETURN(rc);
1852 }
1853
1854 int lprocfs_exp_cleanup(struct obd_export *exp)
1855 {
1856         struct nid_stat *stat = exp->exp_nid_stats;
1857
1858         if(!stat || !exp->exp_obd)
1859                 RETURN(0);
1860
1861         nidstat_putref(exp->exp_nid_stats);
1862         exp->exp_nid_stats = NULL;
1863         lprocfs_free_md_stats(exp->exp_obd);
1864
1865         return 0;
1866 }
1867
1868 int lprocfs_write_helper(const char *buffer, unsigned long count,
1869                          int *val)
1870 {
1871         return lprocfs_write_frac_helper(buffer, count, val, 1);
1872 }
1873
1874 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1875                               int *val, int mult)
1876 {
1877         char kernbuf[20], *end, *pbuf;
1878
1879         if (count > (sizeof(kernbuf) - 1))
1880                 return -EINVAL;
1881
1882         if (copy_from_user(kernbuf, buffer, count))
1883                 return -EFAULT;
1884
1885         kernbuf[count] = '\0';
1886         pbuf = kernbuf;
1887         if (*pbuf == '-') {
1888                 mult = -mult;
1889                 pbuf++;
1890         }
1891
1892         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1893         if (pbuf == end)
1894                 return -EINVAL;
1895
1896         if (end != NULL && *end == '.') {
1897                 int temp_val, pow = 1;
1898                 int i;
1899
1900                 pbuf = end + 1;
1901                 if (strlen(pbuf) > 5)
1902                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
1903
1904                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1905
1906                 if (pbuf < end) {
1907                         for (i = 0; i < (end - pbuf); i++)
1908                                 pow *= 10;
1909
1910                         *val += temp_val / pow;
1911                 }
1912         }
1913         return 0;
1914 }
1915
1916 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
1917                              int mult)
1918 {
1919         long decimal_val, frac_val;
1920         int prtn;
1921
1922         if (count < 10)
1923                 return -EINVAL;
1924
1925         decimal_val = val / mult;
1926         prtn = snprintf(buffer, count, "%ld", decimal_val);
1927         frac_val = val % mult;
1928
1929         if (prtn < (count - 4) && frac_val > 0) {
1930                 long temp_frac;
1931                 int i, temp_mult = 1, frac_bits = 0;
1932
1933                 temp_frac = frac_val * 10;
1934                 buffer[prtn++] = '.';
1935                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
1936                         /* only reserved 2 bits fraction */
1937                         buffer[prtn++] ='0';
1938                         temp_frac *= 10;
1939                         frac_bits++;
1940                 }
1941                 /*
1942                  * Need to think these cases :
1943                  *      1. #echo x.00 > /proc/xxx       output result : x
1944                  *      2. #echo x.0x > /proc/xxx       output result : x.0x
1945                  *      3. #echo x.x0 > /proc/xxx       output result : x.x
1946                  *      4. #echo x.xx > /proc/xxx       output result : x.xx
1947                  *      Only reserved 2 bits fraction.
1948                  */
1949                 for (i = 0; i < (5 - prtn); i++)
1950                         temp_mult *= 10;
1951
1952                 frac_bits = min((int)count - prtn, 3 - frac_bits);
1953                 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
1954                                  frac_val * temp_mult / mult);
1955
1956                 prtn--;
1957                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1958                         prtn--;
1959                         if (buffer[prtn] == '.') {
1960                                 prtn--;
1961                                 break;
1962                         }
1963                 }
1964                 prtn++;
1965         }
1966         buffer[prtn++] ='\n';
1967         return prtn;
1968 }
1969
1970 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1971 {
1972         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1973 }
1974
1975 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1976                               __u64 *val, int mult)
1977 {
1978         char kernbuf[22], *end, *pbuf;
1979         __u64 whole, frac = 0, units;
1980         unsigned frac_d = 1;
1981
1982         if (count > (sizeof(kernbuf) - 1))
1983                 return -EINVAL;
1984
1985         if (copy_from_user(kernbuf, buffer, count))
1986                 return -EFAULT;
1987
1988         kernbuf[count] = '\0';
1989         pbuf = kernbuf;
1990         if (*pbuf == '-') {
1991                 mult = -mult;
1992                 pbuf++;
1993         }
1994
1995         whole = simple_strtoull(pbuf, &end, 10);
1996         if (pbuf == end)
1997                 return -EINVAL;
1998
1999         if (end != NULL && *end == '.') {
2000                 int i;
2001                 pbuf = end + 1;
2002
2003                 /* need to limit frac_d to a __u32 */
2004                 if (strlen(pbuf) > 10)
2005                         pbuf[10] = '\0';
2006
2007                 frac = simple_strtoull(pbuf, &end, 10);
2008                 /* count decimal places */
2009                 for (i = 0; i < (end - pbuf); i++)
2010                         frac_d *= 10;
2011         }
2012
2013         units = 1;
2014         switch(*end) {
2015         case 'p': case 'P':
2016                 units <<= 10;
2017         case 't': case 'T':
2018                 units <<= 10;
2019         case 'g': case 'G':
2020                 units <<= 10;
2021         case 'm': case 'M':
2022                 units <<= 10;
2023         case 'k': case 'K':
2024                 units <<= 10;
2025         }
2026         /* Specified units override the multiplier */
2027         if (units)
2028                 mult = mult < 0 ? -units : units;
2029
2030         frac *= mult;
2031         do_div(frac, frac_d);
2032         *val = whole * mult + frac;
2033         return 0;
2034 }
2035
2036 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, char *name, mode_t mode,
2037                        struct file_operations *seq_fops, void *data)
2038 {
2039         struct proc_dir_entry *entry;
2040         ENTRY;
2041
2042         entry = create_proc_entry(name, mode, parent);
2043         if (entry == NULL)
2044                 RETURN(-ENOMEM);
2045         entry->proc_fops = seq_fops;
2046         entry->data = data;
2047
2048         RETURN(0);
2049 }
2050 EXPORT_SYMBOL(lprocfs_seq_create);
2051
2052 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
2053                                       mode_t mode,
2054                                       struct file_operations *seq_fops,
2055                                       void *data)
2056 {
2057         return (lprocfs_seq_create(dev->obd_proc_entry, name,
2058                                    mode, seq_fops, data));
2059 }
2060 EXPORT_SYMBOL(lprocfs_obd_seq_create);
2061
2062 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
2063 {
2064         if (value >= OBD_HIST_MAX)
2065                 value = OBD_HIST_MAX - 1;
2066
2067         spin_lock(&oh->oh_lock);
2068         oh->oh_buckets[value]++;
2069         spin_unlock(&oh->oh_lock);
2070 }
2071 EXPORT_SYMBOL(lprocfs_oh_tally);
2072
2073 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
2074 {
2075         unsigned int val;
2076
2077         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
2078                 ;
2079
2080         lprocfs_oh_tally(oh, val);
2081 }
2082 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
2083
2084 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
2085 {
2086         unsigned long ret = 0;
2087         int i;
2088
2089         for (i = 0; i < OBD_HIST_MAX; i++)
2090                 ret +=  oh->oh_buckets[i];
2091         return ret;
2092 }
2093 EXPORT_SYMBOL(lprocfs_oh_sum);
2094
2095 void lprocfs_oh_clear(struct obd_histogram *oh)
2096 {
2097         spin_lock(&oh->oh_lock);
2098         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
2099         spin_unlock(&oh->oh_lock);
2100 }
2101 EXPORT_SYMBOL(lprocfs_oh_clear);
2102
2103 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
2104                         int count, int *eof, void *data)
2105 {
2106         struct obd_device *obd = data;
2107         int c = 0;
2108
2109         if (obd == NULL)
2110                 return 0;
2111
2112         c += lustre_hash_debug_header(page, count);
2113         c += lustre_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2114         c += lustre_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2115         c += lustre_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2116
2117         return c;
2118 }
2119 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2120
2121 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2122                                    int count, int *eof, void *data)
2123 {
2124         struct obd_device *obd = data;
2125         int len = 0, size;
2126
2127         LASSERT(obd != NULL);
2128         LASSERT(count >= 0);
2129
2130         /* Set start of user data returned to
2131            page + off since the user may have
2132            requested to read much smaller than
2133            what we need to read */
2134         *start = page + off;
2135
2136         /* We know we are allocated a page here.
2137            Also we know that this function will
2138            not need to write more than a page
2139            so we can truncate at CFS_PAGE_SIZE.  */
2140         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
2141
2142         /* Initialize the page */
2143         memset(page, 0, size);
2144
2145         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2146                 goto out;
2147         if (obd->obd_max_recoverable_clients == 0) {
2148                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2149                         goto out;
2150
2151                 goto fclose;
2152         }
2153
2154         /* sampled unlocked, but really... */
2155         if (obd->obd_recovering == 0) {
2156                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2157                         goto out;
2158                 if (lprocfs_obd_snprintf(&page, size, &len,
2159                                          "recovery_start: %lu\n",
2160                                          obd->obd_recovery_start) <= 0)
2161                         goto out;
2162                 if (lprocfs_obd_snprintf(&page, size, &len,
2163                                          "recovery_duration: %lu\n",
2164                                          obd->obd_recovery_end -
2165                                          obd->obd_recovery_start) <= 0)
2166                         goto out;
2167                 /* Number of clients that have completed recovery */
2168                 if (lprocfs_obd_snprintf(&page, size, &len,
2169                                          "completed_clients: %d/%d\n",
2170                                          obd->obd_max_recoverable_clients -
2171                                          obd->obd_stale_clients,
2172                                          obd->obd_max_recoverable_clients) <= 0)
2173                         goto out;
2174                 if (lprocfs_obd_snprintf(&page, size, &len,
2175                                          "replayed_requests: %d\n",
2176                                          obd->obd_replayed_requests) <= 0)
2177                         goto out;
2178                 if (lprocfs_obd_snprintf(&page, size, &len,
2179                                          "last_transno: "LPD64"\n",
2180                                          obd->obd_next_recovery_transno - 1)<=0)
2181                         goto out;
2182                 if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
2183                                          obd->obd_version_recov ? "ON" : "OFF")<=0)
2184                         goto out;
2185                 goto fclose;
2186         }
2187
2188         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2189                 goto out;
2190         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2191                                  obd->obd_recovery_start) <= 0)
2192                 goto out;
2193         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2194                            cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
2195                            obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
2196                 goto out;
2197         if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2198                                  obd->obd_connected_clients,
2199                                  obd->obd_max_recoverable_clients) <= 0)
2200                 goto out;
2201         /* Number of clients that have completed recovery */
2202         if (lprocfs_obd_snprintf(&page, size, &len,"req_replay_clients: %d\n",
2203                                  atomic_read(&obd->obd_req_replay_clients))<= 0)
2204                 goto out;
2205         if (lprocfs_obd_snprintf(&page, size, &len,"lock_repay_clients: %d\n",
2206                                  atomic_read(&obd->obd_lock_replay_clients))<=0)
2207                 goto out;
2208         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d\n",
2209                                  obd->obd_connected_clients -
2210                                  atomic_read(&obd->obd_lock_replay_clients))<=0)
2211                 goto out;
2212         if (lprocfs_obd_snprintf(&page, size, &len,"evicted_clients: %d\n",
2213                                  obd->obd_stale_clients) <= 0)
2214                 goto out;
2215         if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d\n",
2216                                  obd->obd_replayed_requests) <= 0)
2217                 goto out;
2218         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2219                                  obd->obd_requests_queued_for_recovery) <= 0)
2220                 goto out;
2221
2222         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2223                                  obd->obd_next_recovery_transno) <= 0)
2224                 goto out;
2225
2226 fclose:
2227         *eof = 1;
2228 out:
2229         return min(count, len - (int)off);
2230 }
2231 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2232
2233 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
2234                                     int count, int *eof, void *data)
2235 {
2236         struct obd_device *obd = data;
2237         LASSERT(obd != NULL);
2238
2239         return snprintf(page, count, "%lu\n", obd->obd_recovery_max_time);
2240 }
2241 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
2242
2243 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
2244                                     unsigned long count, void *data)
2245 {
2246         struct obd_device *obd = data;
2247         int val, rc;
2248         LASSERT(obd != NULL);
2249
2250         rc = lprocfs_write_helper(buffer, count, &val);
2251         if (rc)
2252                 return rc;
2253
2254         obd->obd_recovery_max_time = val;
2255         return count;
2256 }
2257 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
2258
2259
2260 /**** Changelogs *****/
2261 #define D_CHANGELOG 0
2262
2263 /* How many records per seq_show.  Too small, we spawn llog_process threads
2264    too often; too large, we run out of buffer space */
2265 #define CHANGELOG_CHUNK_SIZE 100
2266
2267 static int changelog_show_cb(struct llog_handle *llh, struct llog_rec_hdr *hdr,
2268                              void *data)
2269 {
2270         struct seq_file *seq = (struct seq_file *)data;
2271         struct changelog_seq_iter *csi = seq->private;
2272         struct llog_changelog_rec *rec = (struct llog_changelog_rec *)hdr;
2273         char *ptr;
2274         int cnt, rc;
2275         ENTRY;
2276
2277         if ((rec->cr_hdr.lrh_type != CHANGELOG_REC) ||
2278             (rec->cr.cr_type >= CL_LAST)) {
2279                 CERROR("Not a changelog rec %d/%d\n", rec->cr_hdr.lrh_type,
2280                        rec->cr.cr_type);
2281                 RETURN(-EINVAL);
2282         }
2283
2284         CDEBUG(D_CHANGELOG, "rec="LPU64" start="LPU64" cat=%d:%d start=%d:%d\n",
2285                rec->cr.cr_index, csi->csi_startrec,
2286                llh->lgh_hdr->llh_cat_idx, llh->lgh_cur_idx,
2287                csi->csi_startcat, csi->csi_startidx);
2288
2289         if (rec->cr.cr_index < csi->csi_startrec)
2290                 /* Skip entries earlier than what we are interested in */
2291                 RETURN(0);
2292         if (rec->cr.cr_index == csi->csi_startrec) {
2293                 /* Remember where we started, since seq_read will re-read
2294                  * the data when it reallocs space.  Sigh, if only there was
2295                  * a way to tell seq_file how big the buf should be in the
2296                  * first place...
2297                  */
2298                 csi->csi_startcat = llh->lgh_hdr->llh_cat_idx;
2299                 csi->csi_startidx = rec->cr_hdr.lrh_index - 1;
2300         }
2301         if (csi->csi_wrote > CHANGELOG_CHUNK_SIZE) {
2302                 /* Stop at some point with a reasonable seq_file buffer size.
2303                  * Start from here the next time.
2304                  */
2305                 csi->csi_endrec = rec->cr.cr_index - 1;
2306                 csi->csi_startcat = llh->lgh_hdr->llh_cat_idx;
2307                 csi->csi_startidx = rec->cr_hdr.lrh_index - 1;
2308                 csi->csi_wrote = 0;
2309                 RETURN(LLOG_PROC_BREAK);
2310         }
2311
2312         CDEBUG(D_CHANGELOG, LPU64" %02d%-5s "LPU64" 0x%x t="DFID" p="DFID
2313                " %.*s\n", rec->cr.cr_index, rec->cr.cr_type,
2314                changelog_type2str(rec->cr.cr_type), rec->cr.cr_time,
2315                rec->cr.cr_flags & CLF_FLAGMASK,
2316                PFID(&rec->cr.cr_tfid), PFID(&rec->cr.cr_pfid),
2317                rec->cr.cr_namelen, rec->cr.cr_name);
2318
2319         cnt = sizeof(rec->cr) + rec->cr.cr_namelen;
2320         ptr = (char *)(&rec->cr);
2321         CDEBUG(D_CHANGELOG, "packed rec %d starting at %p\n", cnt, ptr);
2322         rc = 0;
2323         while ((cnt-- > 0) && (rc == 0)) {
2324                 rc = seq_putc(seq, *ptr);
2325                 ptr++;
2326         }
2327
2328         if (rc < 0) {
2329                 /* Ran out of room in the seq buffer. seq_read will dump
2330                  * the whole buffer and re-seq_start with a larger one;
2331                  * no point in continuing the llog_process */
2332                 CDEBUG(D_CHANGELOG, "rec="LPU64" overflow "LPU64"<-"LPU64"\n",
2333                        rec->cr.cr_index, csi->csi_startrec, csi->csi_endrec);
2334                 csi->csi_endrec = csi->csi_startrec - 1;
2335                 csi->csi_wrote = 0;
2336                 RETURN(LLOG_PROC_BREAK);
2337         }
2338
2339         csi->csi_wrote++;
2340         csi->csi_endrec = rec->cr.cr_index;
2341
2342         RETURN(0);
2343 }
2344
2345 static int changelog_seq_show(struct seq_file *seq, void *v)
2346 {
2347         struct changelog_seq_iter *csi = seq->private;
2348         int rc;
2349         ENTRY;
2350
2351         if (csi->csi_fill) {
2352                 /* seq_read wants more data to fill his buffer. But we already
2353                    filled the buf as much as we cared to; force seq_read to
2354                    accept that by padding with 0's */
2355                 while (seq_putc(seq, 0) == 0);
2356                 RETURN(0);
2357         }
2358
2359         /* Since we have to restart the llog_cat_process for each chunk of the
2360            seq_ functions, start from where we left off. */
2361         rc = llog_cat_process(csi->csi_llh, changelog_show_cb, seq,
2362                               csi->csi_startcat, csi->csi_startidx);
2363
2364         CDEBUG(D_CHANGELOG,"seq_show "LPU64"-"LPU64" cat=%d:%d wrote=%d rc=%d\n",
2365                csi->csi_startrec, csi->csi_endrec, csi->csi_startcat,
2366                csi->csi_startidx, csi->csi_wrote, rc);
2367
2368         if (rc == 0)
2369                 csi->csi_done = 1;
2370         if (rc == LLOG_PROC_BREAK)
2371                 /* more records left, but seq_show must return 0 */
2372                 rc = 0;
2373         RETURN(rc);
2374 }
2375
2376 static void *changelog_seq_start(struct seq_file *seq, loff_t *pos)
2377 {
2378         struct changelog_seq_iter *csi = seq->private;
2379         LASSERT(csi);
2380
2381         CDEBUG(D_CHANGELOG, "start "LPU64"-"LPU64" pos="LPU64"\n",
2382                csi->csi_startrec, csi->csi_endrec, *pos);
2383
2384         csi->csi_fill = 0;
2385
2386         if (csi->csi_done)
2387                 /* no more records, seq_read should return 0 if buffer
2388                    is empty */
2389                 return NULL;
2390
2391         if (*pos > csi->csi_pos) {
2392                 /* The seq_read implementation sucks.  It may call start
2393                    multiple times, using pos to indicate advances, if any,
2394                    by arbitrarily increasing it by 1. So ignore the actual
2395                    value of pos, and just register any increase as
2396                    "seq_read wants the next values". */
2397                 csi->csi_startrec = csi->csi_endrec + 1;
2398                 csi->csi_pos = *pos;
2399         }
2400         /* else use old startrec/startidx */
2401
2402         return csi;
2403 }
2404
2405 static void changelog_seq_stop(struct seq_file *seq, void *v)
2406 {
2407         struct changelog_seq_iter *csi = seq->private;
2408
2409         CDEBUG(D_CHANGELOG, "stop "LPU64"-"LPU64"\n",
2410                csi->csi_startrec, csi->csi_endrec);
2411 }
2412
2413 static void *changelog_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2414 {
2415         struct changelog_seq_iter *csi = seq->private;
2416
2417         CDEBUG(D_CHANGELOG, "next "LPU64"-"LPU64" pos="LPU64"\n",
2418                csi->csi_startrec, csi->csi_endrec, *pos);
2419
2420         csi->csi_fill = 1;
2421
2422         return csi;
2423 }
2424
2425 static struct seq_operations changelog_sops = {
2426         .start = changelog_seq_start,
2427         .stop = changelog_seq_stop,
2428         .next = changelog_seq_next,
2429         .show = changelog_seq_show,
2430 };
2431
2432 int changelog_seq_open(struct inode *inode, struct file *file,
2433                        struct changelog_seq_iter **csih)
2434 {
2435         struct changelog_seq_iter *csi;
2436         struct proc_dir_entry *dp = PDE(inode);
2437         struct seq_file *seq;
2438         int rc;
2439
2440         LPROCFS_ENTRY_AND_CHECK(dp);
2441
2442         rc = seq_open(file, &changelog_sops);
2443         if (rc) {
2444                 LPROCFS_EXIT();
2445                 return rc;
2446         }
2447
2448         OBD_ALLOC_PTR(csi);
2449         if (csi == NULL) {
2450                 lprocfs_seq_release(inode, file);
2451                 return -ENOMEM;
2452         }
2453
2454         csi->csi_dev = dp->data;
2455         seq = file->private_data;
2456         seq->private = csi;
2457         *csih = csi;
2458
2459         return rc;
2460 }
2461 EXPORT_SYMBOL(changelog_seq_open);
2462
2463 int changelog_seq_release(struct inode *inode, struct file *file)
2464 {
2465         struct seq_file *seq = file->private_data;
2466         struct changelog_seq_iter *csi = seq->private;
2467
2468         if (csi)
2469                 OBD_FREE_PTR(csi);
2470
2471         return lprocfs_seq_release(inode, file);
2472 }
2473 EXPORT_SYMBOL(changelog_seq_release);
2474
2475 #ifndef SEEK_CUR /* SLES10 needs this */
2476 #define SEEK_CUR        1
2477 #define SEEK_END        2
2478 #endif
2479
2480 loff_t changelog_seq_lseek(struct file *file, loff_t offset, int origin)
2481 {
2482         struct seq_file *seq = (struct seq_file *)file->private_data;
2483         struct changelog_seq_iter *csi = seq->private;
2484
2485         CDEBUG(D_CHANGELOG,"seek "LPU64"-"LPU64" off="LPU64":%d fpos="LPU64"\n",
2486                csi->csi_startrec, csi->csi_endrec, offset, origin, file->f_pos);
2487
2488         LL_SEQ_LOCK(seq);
2489
2490         switch (origin) {
2491                 case SEEK_CUR:
2492                         offset += csi->csi_endrec;
2493                         break;
2494                 case SEEK_END:
2495                         /* we don't know the last rec */
2496                         offset = -1;
2497         }
2498
2499         /* SEEK_SET */
2500
2501         if (offset < 0) {
2502                 LL_SEQ_UNLOCK(seq);
2503                 return -EINVAL;
2504         }
2505
2506         csi->csi_startrec = offset;
2507         csi->csi_endrec = offset ? offset - 1 : 0;
2508
2509         /* drop whatever is left in sucky seq_read's buffer */
2510         seq->count = 0;
2511         seq->from = 0;
2512         seq->index++;
2513         LL_SEQ_UNLOCK(seq);
2514         file->f_pos = csi->csi_startrec;
2515         return csi->csi_startrec;
2516 }
2517 EXPORT_SYMBOL(changelog_seq_lseek);
2518
2519 EXPORT_SYMBOL(lprocfs_register);
2520 EXPORT_SYMBOL(lprocfs_srch);
2521 EXPORT_SYMBOL(lprocfs_remove);
2522 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
2523 EXPORT_SYMBOL(lprocfs_add_vars);
2524 EXPORT_SYMBOL(lprocfs_obd_setup);
2525 EXPORT_SYMBOL(lprocfs_obd_cleanup);
2526 EXPORT_SYMBOL(lprocfs_add_simple);
2527 EXPORT_SYMBOL(lprocfs_add_symlink);
2528 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
2529 EXPORT_SYMBOL(lprocfs_alloc_stats);
2530 EXPORT_SYMBOL(lprocfs_free_stats);
2531 EXPORT_SYMBOL(lprocfs_clear_stats);
2532 EXPORT_SYMBOL(lprocfs_register_stats);
2533 EXPORT_SYMBOL(lprocfs_init_ops_stats);
2534 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
2535 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
2536 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
2537 EXPORT_SYMBOL(lprocfs_free_obd_stats);
2538 EXPORT_SYMBOL(lprocfs_exp_setup);
2539 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2540
2541 EXPORT_SYMBOL(lprocfs_rd_u64);
2542 EXPORT_SYMBOL(lprocfs_rd_atomic);
2543 EXPORT_SYMBOL(lprocfs_wr_atomic);
2544 EXPORT_SYMBOL(lprocfs_rd_uint);
2545 EXPORT_SYMBOL(lprocfs_wr_uint);
2546 EXPORT_SYMBOL(lprocfs_rd_uuid);
2547 EXPORT_SYMBOL(lprocfs_rd_name);
2548 EXPORT_SYMBOL(lprocfs_rd_fstype);
2549 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
2550 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
2551 EXPORT_SYMBOL(lprocfs_rd_num_exports);
2552 EXPORT_SYMBOL(lprocfs_rd_numrefs);
2553 EXPORT_SYMBOL(lprocfs_at_hist_helper);
2554 EXPORT_SYMBOL(lprocfs_rd_import);
2555 EXPORT_SYMBOL(lprocfs_rd_state);
2556 EXPORT_SYMBOL(lprocfs_rd_timeouts);
2557 EXPORT_SYMBOL(lprocfs_rd_blksize);
2558 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
2559 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
2560 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
2561 EXPORT_SYMBOL(lprocfs_rd_filestotal);
2562 EXPORT_SYMBOL(lprocfs_rd_filesfree);
2563 EXPORT_SYMBOL(lprocfs_rd_quota_resend_count);
2564 EXPORT_SYMBOL(lprocfs_wr_quota_resend_count);
2565
2566 EXPORT_SYMBOL(lprocfs_write_helper);
2567 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2568 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2569 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2570 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
2571 EXPORT_SYMBOL(lprocfs_stats_collect);
2572 #endif /* LPROCFS*/