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