Whamcloud - gitweb
Directly associate cached pages to lock that protect those pages,
[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, queue_async_io);
1072         LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
1073         LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
1074         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
1075         LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
1076         LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1077         LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1078         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1079         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1080         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1081         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1082         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1083         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1084         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1085         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1086         LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
1087         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1088         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1089         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1090         LPROCFS_OBD_OP_INIT(num_private_stats, stats, join_lru);
1091         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1092         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1093         LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1094         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1095         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1096         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1097         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1098         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1099         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1100         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1101         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1102         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1103         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1104         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1105         LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_page_removal_cb);
1106         LPROCFS_OBD_OP_INIT(num_private_stats,stats,unregister_page_removal_cb);
1107         LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_lock_cancel_cb);
1108         LPROCFS_OBD_OP_INIT(num_private_stats, stats,unregister_lock_cancel_cb);
1109 }
1110
1111 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1112 {
1113         struct lprocfs_stats *stats;
1114         unsigned int num_stats;
1115         int rc, i;
1116
1117         LASSERT(obd->obd_stats == NULL);
1118         LASSERT(obd->obd_proc_entry != NULL);
1119         LASSERT(obd->obd_cntr_base == 0);
1120
1121         num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1122                 num_private_stats - 1 /* o_owner */;
1123         stats = lprocfs_alloc_stats(num_stats, 0);
1124         if (stats == NULL)
1125                 return -ENOMEM;
1126
1127         lprocfs_init_ops_stats(num_private_stats, stats);
1128
1129         for (i = num_private_stats; i < num_stats; i++) {
1130                 /* If this LBUGs, it is likely that an obd
1131                  * operation was added to struct obd_ops in
1132                  * <obd.h>, and that the corresponding line item
1133                  * LPROCFS_OBD_OP_INIT(.., .., opname)
1134                  * is missing from the list above. */
1135                 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1136                          "Missing obd_stat initializer obd_op "
1137                          "operation at offset %d.\n", i - num_private_stats);
1138         }
1139         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1140         if (rc < 0) {
1141                 lprocfs_free_stats(&stats);
1142         } else {
1143                 obd->obd_stats  = stats;
1144                 obd->obd_cntr_base = num_private_stats;
1145         }
1146         return rc;
1147 }
1148
1149 void lprocfs_free_obd_stats(struct obd_device *obd)
1150 {
1151         if (obd->obd_stats) 
1152                 lprocfs_free_stats(&obd->obd_stats);
1153 }
1154
1155 #define LPROCFS_MD_OP_INIT(base, stats, op)                             \
1156 do {                                                                    \
1157         unsigned int coffset = base + MD_COUNTER_OFFSET(op);            \
1158         LASSERT(coffset < stats->ls_num);                               \
1159         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
1160 } while (0)
1161
1162 int lprocfs_alloc_md_stats(struct obd_device *obd,
1163                            unsigned num_private_stats)
1164 {
1165         struct lprocfs_stats *stats;
1166         unsigned int num_stats;
1167         int rc, i;
1168
1169         LASSERT(obd->md_stats == NULL);
1170         LASSERT(obd->obd_proc_entry != NULL);
1171         LASSERT(obd->md_cntr_base == 0);
1172
1173         num_stats = 1 + MD_COUNTER_OFFSET(get_remote_perm) +
1174                     num_private_stats;
1175         stats = lprocfs_alloc_stats(num_stats, 0);
1176         if (stats == NULL)
1177                 return -ENOMEM;
1178
1179         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1180         LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1181         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1182         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1183         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1184         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1185         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1186         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1187         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1188         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1189         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1190         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1191         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1192         LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1193         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1194         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1195         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1196         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1197         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1198         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1199         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1200         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1201         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1202         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1203         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1204         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1205         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1206         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1207         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1208         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1209
1210         for (i = num_private_stats; i < num_stats; i++) {
1211                 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1212                         CERROR("Missing md_stat initializer md_op "
1213                                "operation at offset %d. Aborting.\n",
1214                                i - num_private_stats);
1215                         LBUG();
1216                 }
1217         }
1218         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1219         if (rc < 0) {
1220                 lprocfs_free_stats(&stats);
1221         } else {
1222                 obd->md_stats  = stats;
1223                 obd->md_cntr_base = num_private_stats;
1224         }
1225         return rc;
1226 }
1227
1228 void lprocfs_free_md_stats(struct obd_device *obd)
1229 {
1230         struct lprocfs_stats *stats = obd->md_stats;
1231
1232         if (stats != NULL) {
1233                 obd->md_stats = NULL;
1234                 lprocfs_free_stats(&stats);
1235         }
1236 }
1237
1238 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1239                          int *eof,  void *data)
1240 {
1241         struct obd_export *exp = (struct obd_export*)data;
1242         LASSERT(exp != NULL);
1243         *eof = 1;
1244         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1245 }
1246
1247 struct exp_uuid_cb_data {
1248         char                   *page;
1249         int                     count;
1250         int                    *eof;
1251         int                    *len;
1252 };
1253
1254 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1255 {
1256         struct obd_export *exp = (struct obd_export *)obj;
1257         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1258
1259         if (exp->exp_nid_stats)
1260                 *data->len += snprintf((data->page + *data->len),
1261                                        data->count, "%s\n",
1262                                        obd_uuid2str(&exp->exp_client_uuid));
1263 }
1264
1265 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1266                         int *eof,  void *data)
1267 {
1268         struct nid_stat *stats = (struct nid_stat *)data;
1269         struct exp_uuid_cb_data cb_data;
1270         struct obd_device *obd = stats->nid_obd;
1271         int len = 0;
1272
1273         *eof = 1;
1274         page[0] = '\0';
1275         LASSERT(obd != NULL);
1276
1277         cb_data.page = page;
1278         cb_data.count = count;
1279         cb_data.eof = eof;
1280         cb_data.len = &len;
1281         lustre_hash_bucket_iterate(obd->obd_nid_hash_body,
1282                                    &stats->nid, lprocfs_exp_print_uuid,
1283                                    &cb_data);
1284         return (*cb_data.len);
1285 }
1286
1287 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1288                                         int count, int *eof,  void *data)
1289 {
1290         *eof = 1;
1291         return snprintf(page, count, "%s\n",
1292                         "Write into this file to clear all nid stats and "
1293                         "stale nid entries");
1294 }
1295 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1296
1297 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1298 {
1299         struct nid_stat *stat = obj;
1300         int i;
1301
1302         /* object has only hash + iterate_all references.
1303          * add/delete blocked by hash bucket lock */
1304         CDEBUG(D_INFO,"refcnt %d\n", stat->nid_exp_ref_count);
1305         if(stat->nid_exp_ref_count == 2) {
1306                 hlist_del_init(&stat->nid_hash);
1307                 stat->nid_exp_ref_count--;
1308                 spin_lock(&stat->nid_obd->obd_nid_lock);
1309                 list_del_init(&stat->nid_list);
1310                 spin_unlock(&stat->nid_obd->obd_nid_lock);
1311                 list_add(&stat->nid_list, data);
1312                 EXIT;
1313                 return;
1314         }
1315         /* we has reference to object - only clear data*/
1316         if (stat->nid_stats)
1317                 lprocfs_clear_stats(stat->nid_stats);
1318
1319         if (stat->nid_brw_stats) {
1320                 for (i = 0; i < BRW_LAST; i++)
1321                         lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1322         }
1323         EXIT;
1324         return;
1325 }
1326
1327 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1328                                          unsigned long count, void *data)
1329 {
1330         struct obd_device *obd = (struct obd_device *)data;
1331         struct nid_stat *client_stat;
1332         CFS_LIST_HEAD(free_list);
1333
1334         lustre_hash_iterate_all(obd->obd_nid_stats_hash_body,
1335                                 lprocfs_nid_stats_clear_write_cb, &free_list);
1336
1337         while (!list_empty(&free_list)) {
1338                 client_stat = list_entry(free_list.next, struct nid_stat, nid_list);
1339                 list_del_init(&client_stat->nid_list);
1340                 lprocfs_free_client_stats(client_stat);
1341         }
1342
1343         return count;
1344 }
1345 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1346
1347 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1348 {
1349         int rc = 0;
1350         struct nid_stat *tmp = NULL, *tmp1;
1351         struct obd_device *obd = NULL;
1352         ENTRY;
1353
1354         *newnid = 0;
1355
1356         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1357             !exp->exp_obd->obd_nid_stats_hash_body)
1358                 RETURN(-EINVAL);
1359
1360         /* not test against zero because eric say:
1361          * You may only test nid against another nid, or LNET_NID_ANY.  Anything else is
1362          * nonsense.*/
1363         if (!nid || *nid == LNET_NID_ANY)
1364                 RETURN(0);
1365
1366         obd = exp->exp_obd;
1367
1368         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash_body);
1369
1370         OBD_ALLOC(tmp, sizeof(struct nid_stat));
1371         if (tmp == NULL)
1372                 RETURN(-ENOMEM);
1373
1374         tmp->nid = *nid;
1375         tmp->nid_obd = exp->exp_obd;
1376         tmp->nid_exp_ref_count = 1; /* need live in hash after destroy export */
1377
1378        /* protect competitive add to list, not need locking on destroy */
1379         spin_lock(&obd->obd_nid_lock);
1380         list_add(&tmp->nid_list, &obd->obd_nid_stats);
1381         spin_unlock(&obd->obd_nid_lock);
1382
1383         tmp1= lustre_hash_findadd_unique(obd->obd_nid_stats_hash_body, nid,
1384                                          &tmp->nid_hash);
1385         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1386                tmp1, libcfs_nid2str(*nid), tmp->nid_exp_ref_count);
1387
1388         if (tmp1 != tmp) {
1389                 exp->exp_nid_stats = tmp1;
1390                 GOTO(destroy_new, rc = 0);
1391         }
1392         /* not found - create */
1393         tmp->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1394                                          obd->obd_proc_exports_entry, NULL, NULL);
1395         if (!tmp->nid_proc) {
1396                 CERROR("Error making export directory for"
1397                        " nid %s\n", libcfs_nid2str(*nid));
1398                 lustre_hash_delitem(obd->obd_nid_stats_hash_body, nid,
1399                                     &tmp->nid_hash);
1400                 GOTO(destroy_new, rc = -ENOMEM);
1401         }
1402
1403         rc = lprocfs_add_simple(tmp->nid_proc, "uuid",
1404                                 lprocfs_exp_rd_uuid, NULL, tmp);
1405         if (rc)
1406                 CWARN("Error adding the uuid file\n");
1407
1408         exp->exp_nid_stats = tmp;
1409         *newnid = 1;
1410         RETURN(rc);
1411
1412 destroy_new:
1413         spin_lock(&obd->obd_nid_lock);
1414         list_del(&tmp->nid_list);
1415         spin_unlock(&obd->obd_nid_lock);
1416         OBD_FREE(tmp, sizeof(struct nid_stat));
1417         RETURN(rc);
1418 }
1419
1420 int lprocfs_exp_cleanup(struct obd_export *exp)
1421 {
1422         struct nid_stat *stat = exp->exp_nid_stats;
1423
1424         if(!stat)
1425                 RETURN(0);
1426
1427         stat->nid_exp_ref_count--;
1428         CDEBUG(D_INFO, "Put stat %p - %d\n", stat, stat->nid_exp_ref_count);
1429
1430         exp->exp_nid_stats = NULL;
1431         return 0;
1432 }
1433
1434 int lprocfs_write_helper(const char *buffer, unsigned long count,
1435                          int *val)
1436 {
1437         return lprocfs_write_frac_helper(buffer, count, val, 1);
1438 }
1439
1440 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1441                               int *val, int mult)
1442 {
1443         char kernbuf[20], *end, *pbuf;
1444
1445         if (count > (sizeof(kernbuf) - 1))
1446                 return -EINVAL;
1447
1448         if (copy_from_user(kernbuf, buffer, count))
1449                 return -EFAULT;
1450
1451         kernbuf[count] = '\0';
1452         pbuf = kernbuf;
1453         if (*pbuf == '-') {
1454                 mult = -mult;
1455                 pbuf++;
1456         }
1457
1458         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1459         if (pbuf == end)
1460                 return -EINVAL;
1461
1462         if (end != NULL && *end == '.') {
1463                 int temp_val, pow = 1;
1464                 int i;
1465
1466                 pbuf = end + 1;
1467                 if (strlen(pbuf) > 5)
1468                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
1469
1470                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1471
1472                 if (pbuf < end) {
1473                         for (i = 0; i < (end - pbuf); i++)
1474                                 pow *= 10;
1475
1476                         *val += temp_val / pow;
1477                 }
1478         }
1479         return 0;
1480 }
1481
1482 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1483 {
1484         long decimal_val, frac_val;
1485         int prtn;
1486
1487         if (count < 10)
1488                 return -EINVAL;
1489
1490         decimal_val = val / mult;
1491         prtn = snprintf(buffer, count, "%ld", decimal_val);
1492         frac_val = val % mult;
1493
1494         if (prtn < (count - 4) && frac_val > 0) {
1495                 long temp_frac;
1496                 int i, temp_mult = 1, frac_bits = 0;
1497
1498                 temp_frac = frac_val * 10;
1499                 buffer[prtn++] = '.';
1500                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) { /*only reserved 2bits fraction*/
1501                         buffer[prtn++] ='0';
1502                         temp_frac *= 10;
1503                         frac_bits++;
1504                 }
1505                 /*
1506                   Need to think these cases :
1507                         1. #echo x.00 > /proc/xxx       output result : x
1508                         2. #echo x.0x > /proc/xxx       output result : x.0x
1509                         3. #echo x.x0 > /proc/xxx       output result : x.x
1510                         4. #echo x.xx > /proc/xxx       output result : x.xx
1511                         Only reserved 2bits fraction.       
1512                  */
1513                 for (i = 0; i < (5 - prtn); i++)
1514                         temp_mult *= 10;
1515
1516                 frac_bits = min((int)count - prtn, 3 - frac_bits);
1517                 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1518
1519                 prtn--;
1520                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1521                         prtn--;
1522                         if (buffer[prtn] == '.') {
1523                                 prtn--;
1524                                 break;
1525                         }
1526                 }
1527                 prtn++;
1528         }
1529         buffer[prtn++] ='\n';
1530         return prtn;
1531 }
1532
1533 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1534 {
1535         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1536 }
1537
1538 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1539                               __u64 *val, int mult)
1540 {
1541         char kernbuf[22], *end, *pbuf;
1542         __u64 whole, frac = 0, units;
1543         unsigned frac_d = 1;
1544
1545         if (count > (sizeof(kernbuf) - 1) )
1546                 return -EINVAL;
1547
1548         if (copy_from_user(kernbuf, buffer, count))
1549                 return -EFAULT;
1550
1551         kernbuf[count] = '\0';
1552         pbuf = kernbuf;
1553         if (*pbuf == '-') {
1554                 mult = -mult;
1555                 pbuf++;
1556         }
1557
1558         whole = simple_strtoull(pbuf, &end, 10);
1559         if (pbuf == end)
1560                 return -EINVAL;
1561
1562         if (end != NULL && *end == '.') {
1563                 int i;
1564                 pbuf = end + 1;
1565
1566                 /* need to limit frac_d to a __u32 */
1567                 if (strlen(pbuf) > 10)
1568                         pbuf[10] = '\0';
1569
1570                 frac = simple_strtoull(pbuf, &end, 10);
1571                 /* count decimal places */
1572                 for (i = 0; i < (end - pbuf); i++)
1573                         frac_d *= 10;
1574         }
1575
1576         units = 1;
1577         switch(*end) {
1578         case 'p': case 'P':
1579                 units <<= 10;
1580         case 't': case 'T':
1581                 units <<= 10;
1582         case 'g': case 'G':
1583                 units <<= 10;
1584         case 'm': case 'M':
1585                 units <<= 10;
1586         case 'k': case 'K':
1587                 units <<= 10;
1588         }
1589         /* Specified units override the multiplier */
1590         if (units) 
1591                 mult = mult < 0 ? -units : units;
1592
1593         frac *= mult;
1594         do_div(frac, frac_d);
1595         *val = whole * mult + frac;
1596         return 0;
1597 }
1598
1599 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, 
1600                        char *name, mode_t mode,
1601                        struct file_operations *seq_fops, void *data)
1602 {
1603         struct proc_dir_entry *entry;
1604         ENTRY;
1605
1606         entry = create_proc_entry(name, mode, parent);
1607         if (entry == NULL)
1608                 RETURN(-ENOMEM);
1609         entry->proc_fops = seq_fops;
1610         entry->data = data;
1611
1612         RETURN(0);
1613 }
1614 EXPORT_SYMBOL(lprocfs_seq_create);
1615
1616 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1617                                       mode_t mode,
1618                                       struct file_operations *seq_fops,
1619                                       void *data)
1620 {
1621         return (lprocfs_seq_create(dev->obd_proc_entry, name, 
1622                                    mode, seq_fops, data));
1623 }
1624 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1625
1626 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1627 {
1628         if (value >= OBD_HIST_MAX)
1629                 value = OBD_HIST_MAX - 1;
1630
1631         spin_lock(&oh->oh_lock);
1632         oh->oh_buckets[value]++;
1633         spin_unlock(&oh->oh_lock);
1634 }
1635 EXPORT_SYMBOL(lprocfs_oh_tally);
1636
1637 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1638 {
1639         unsigned int val;
1640
1641         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1642                 ;
1643
1644         lprocfs_oh_tally(oh, val);
1645 }
1646 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1647
1648 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1649 {
1650         unsigned long ret = 0;
1651         int i;
1652
1653         for (i = 0; i < OBD_HIST_MAX; i++)
1654                 ret +=  oh->oh_buckets[i];
1655         return ret;
1656 }
1657 EXPORT_SYMBOL(lprocfs_oh_sum);
1658
1659 void lprocfs_oh_clear(struct obd_histogram *oh)
1660 {
1661         spin_lock(&oh->oh_lock);
1662         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1663         spin_unlock(&oh->oh_lock);
1664 }
1665 EXPORT_SYMBOL(lprocfs_oh_clear);
1666
1667 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1668                                    int count, int *eof, void *data)
1669 {
1670         struct obd_device *obd = data;
1671         int len = 0, size;
1672
1673         LASSERT(obd != NULL);
1674         LASSERT(count >= 0);
1675
1676         /* Set start of user data returned to
1677            page + off since the user may have
1678            requested to read much smaller than
1679            what we need to read */
1680         *start = page + off;
1681
1682         /* We know we are allocated a page here.
1683            Also we know that this function will
1684            not need to write more than a page
1685            so we can truncate at CFS_PAGE_SIZE.  */
1686         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
1687
1688         /* Initialize the page */
1689         memset(page, 0, size);
1690
1691         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
1692                 goto out;
1693
1694         if (obd->obd_max_recoverable_clients == 0) {
1695                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
1696                         goto out;
1697
1698                 goto fclose;
1699         }
1700
1701         /* sampled unlocked, but really... */
1702         if (obd->obd_recovering == 0) {
1703                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
1704                         goto out;
1705
1706                 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1707                     obd->obd_recovery_start) <= 0)
1708                         goto out;
1709
1710                 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_end: %lu\n",
1711                     obd->obd_recovery_end) <= 0)
1712                         goto out;
1713
1714                 /* Number of clients have have completed recovery */
1715                 if (lprocfs_obd_snprintf(&page, size, &len, "recovered_clients: %d\n",
1716                     obd->obd_max_recoverable_clients - obd->obd_recoverable_clients) <= 0)
1717                         goto out;
1718
1719                 if (lprocfs_obd_snprintf(&page, size, &len, "unrecovered_clients: %d\n",
1720                     obd->obd_recoverable_clients) <= 0)
1721                         goto out;
1722
1723                 if (lprocfs_obd_snprintf(&page, size, &len, "last_transno: "LPD64"\n",
1724                     obd->obd_next_recovery_transno - 1) <= 0)
1725                         goto out;
1726
1727                 lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d\n", obd->obd_replayed_requests);
1728                 goto fclose;
1729         }
1730
1731         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
1732                 goto out;
1733
1734         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1735             obd->obd_recovery_start) <= 0)
1736                 goto out;
1737
1738         if (lprocfs_obd_snprintf(&page, size, &len, "time remaining: %lu\n",
1739                                  cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
1740                                  obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
1741                 goto out;
1742
1743         if(lprocfs_obd_snprintf(&page, size, &len, "connected_clients: %d/%d\n",
1744                                 obd->obd_connected_clients,
1745                                 obd->obd_max_recoverable_clients) <= 0)
1746                 goto out;
1747
1748         /* Number of clients have have completed recovery */
1749         if (lprocfs_obd_snprintf(&page, size, &len, "completed_clients: %d/%d\n",
1750                                  obd->obd_max_recoverable_clients - obd->obd_recoverable_clients,
1751                                  obd->obd_max_recoverable_clients) <= 0)
1752                 goto out;
1753
1754         if (lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d/??\n",
1755                                  obd->obd_replayed_requests) <= 0)
1756                 goto out;
1757
1758         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1759                                  obd->obd_requests_queued_for_recovery) <= 0)
1760                 goto out;
1761
1762         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n", 
1763                                  obd->obd_next_recovery_transno) <= 0)
1764                 goto out;
1765
1766 fclose:
1767         *eof = 1;
1768 out:
1769         return min(count, len - (int)off);
1770 }
1771 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1772
1773 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
1774                                     int count, int *eof, void *data)
1775 {
1776         struct obd_device *obd = (struct obd_device *)data;
1777         LASSERT(obd != NULL);
1778
1779         return snprintf(page, count, "%lu\n", 
1780                         obd->obd_recovery_max_time);
1781 }
1782 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
1783
1784 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
1785                                     unsigned long count, void *data)
1786 {
1787         struct obd_device *obd = (struct obd_device *)data;
1788         int val, rc;
1789         LASSERT(obd != NULL);
1790
1791         rc = lprocfs_write_helper(buffer, count, &val);
1792         if (rc)
1793                 return rc;
1794
1795         obd->obd_recovery_max_time = val;
1796         return count;
1797 }
1798 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
1799
1800 EXPORT_SYMBOL(lprocfs_register);
1801 EXPORT_SYMBOL(lprocfs_srch);
1802 EXPORT_SYMBOL(lprocfs_remove);
1803 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
1804 EXPORT_SYMBOL(lprocfs_add_vars);
1805 EXPORT_SYMBOL(lprocfs_obd_setup);
1806 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1807 EXPORT_SYMBOL(lprocfs_add_simple);
1808 EXPORT_SYMBOL(lprocfs_add_symlink);
1809 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
1810 EXPORT_SYMBOL(lprocfs_alloc_stats);
1811 EXPORT_SYMBOL(lprocfs_free_stats);
1812 EXPORT_SYMBOL(lprocfs_clear_stats);
1813 EXPORT_SYMBOL(lprocfs_register_stats);
1814 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1815 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1816 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1817 EXPORT_SYMBOL(lprocfs_exp_setup);
1818 EXPORT_SYMBOL(lprocfs_exp_cleanup);
1819
1820 EXPORT_SYMBOL(lprocfs_rd_u64);
1821 EXPORT_SYMBOL(lprocfs_rd_atomic);
1822 EXPORT_SYMBOL(lprocfs_wr_atomic);
1823 EXPORT_SYMBOL(lprocfs_rd_uint);
1824 EXPORT_SYMBOL(lprocfs_wr_uint);
1825 EXPORT_SYMBOL(lprocfs_rd_uuid);
1826 EXPORT_SYMBOL(lprocfs_rd_name);
1827 EXPORT_SYMBOL(lprocfs_rd_fstype);
1828 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
1829 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
1830 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1831 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1832
1833 EXPORT_SYMBOL(lprocfs_rd_blksize);
1834 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
1835 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
1836 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
1837 EXPORT_SYMBOL(lprocfs_rd_filestotal);
1838 EXPORT_SYMBOL(lprocfs_rd_filesfree);
1839
1840 EXPORT_SYMBOL(lprocfs_write_helper);
1841 EXPORT_SYMBOL(lprocfs_write_frac_helper);
1842 EXPORT_SYMBOL(lprocfs_read_frac_helper);
1843 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1844 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
1845 #endif /* LPROCFS*/