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