Whamcloud - gitweb
merge b_devel into HEAD (20030626 merge tag) for 0.7.1
[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 Lustre, http://www.lustre.org.
8  *
9  *   Lustre is free software; you can redistribute it and/or
10  *   modify it under the terms of version 2 of the GNU General Public
11  *   License as published by the Free Software Foundation.
12  *
13  *   Lustre is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with Lustre; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22
23 #define EXPORT_SYMTAB
24 #define DEBUG_SUBSYSTEM S_CLASS
25 #ifdef __KERNEL__
26 #include <linux/config.h>
27 #include <linux/module.h>
28 #include <linux/version.h>
29 #include <linux/slab.h>
30 #include <linux/types.h>
31 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
32 #include <asm/statfs.h>
33 #endif
34 #include <linux/seq_file.h>
35
36 #else
37 #include <liblustre.h>
38 #endif
39
40 #include <linux/obd_class.h>
41 #include <linux/lprocfs_status.h>
42
43 #ifdef LPROCFS
44
45 struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
46                                     const char *name)
47 {
48         struct proc_dir_entry* temp;
49
50         if (!head)
51                 return NULL;
52
53         temp = head->subdir;
54         while (temp != NULL) {
55                 if (!strcmp(temp->name, name))
56                         return temp;
57
58                 temp = temp->next;
59         }
60         return NULL;
61 }
62
63 /* lprocfs API calls */
64
65 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
66                      void *data)
67 {
68         if ((root == NULL) || (list == NULL))
69                 return -EINVAL;
70
71         while (list->name) {
72                 struct proc_dir_entry *cur_root, *proc;
73                 char *pathcopy, *cur, *next;
74                 int pathsize = strlen(list->name)+1;
75
76                 proc = NULL;
77                 cur_root = root;
78
79                 /* need copy of path for strsep */
80                 OBD_ALLOC(pathcopy, pathsize);
81                 if (!pathcopy)
82                         return -ENOMEM;
83
84                 next = pathcopy;
85                 strcpy(pathcopy, list->name);
86
87                 while (cur_root && (cur = strsep(&next, "/"))) {
88                         if (*cur =='\0') /* skip double/trailing "/" */
89                                 continue;
90
91                         proc = lprocfs_srch(cur_root, cur);
92                         CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
93                                cur_root->name, cur, next,
94                                (proc ? "exists" : "new"));
95                         if (next)
96                                 cur_root = (proc ? proc :
97                                                    proc_mkdir(cur, cur_root));
98                         else if (!proc)
99                                 proc = create_proc_entry(cur, 0444, cur_root);
100                 }
101
102                 OBD_FREE(pathcopy, pathsize);
103
104                 if ((cur_root == NULL) || (proc == NULL)) {
105                         CERROR("LprocFS: No memory to create /proc entry %s",
106                                list->name);
107                         return -ENOMEM;
108                 }
109
110                 proc->read_proc = list->read_fptr;
111                 proc->write_proc = list->write_fptr;
112                 proc->data = (list->data ? list->data : data);
113                 list++;
114         }
115         return 0;
116 }
117
118 void lprocfs_remove(struct proc_dir_entry* root)
119 {
120         struct proc_dir_entry *temp = root;
121         struct proc_dir_entry *rm_entry;
122         struct proc_dir_entry *parent;
123
124         LASSERT(root != NULL);
125         parent = root->parent;
126         LASSERT(parent != NULL);
127
128         while (1) {
129                 while (temp->subdir)
130                         temp = temp->subdir;
131
132                 rm_entry = temp;
133                 temp = temp->parent;
134                 remove_proc_entry(rm_entry->name, rm_entry->parent);
135                 if (temp == parent)
136                         break;
137         }
138 }
139
140 struct proc_dir_entry *lprocfs_register(const char *name,
141                                         struct proc_dir_entry *parent,
142                                         struct lprocfs_vars *list, void *data)
143 {
144         struct proc_dir_entry *newchild;
145
146         newchild = lprocfs_srch(parent, name);
147         if (newchild) {
148                 CERROR(" Lproc: Attempting to register %s more than once \n",
149                        name);
150                 return ERR_PTR(-EALREADY);
151         }
152
153         newchild = proc_mkdir(name, parent);
154         if (newchild && list) {
155                 int rc = lprocfs_add_vars(newchild, list, data);
156                 if (rc) {
157                         lprocfs_remove(newchild);
158                         return ERR_PTR(rc);
159                 }
160         }
161         return newchild;
162 }
163
164 /* Generic callbacks */
165
166 int lprocfs_rd_u64(char *page, char **start, off_t off,
167                    int count, int *eof, void *data)
168 {
169         LASSERT(data != NULL);
170         *eof = 1;
171         return snprintf(page, count, LPU64"\n", *(__u64 *)data);
172 }
173
174 int lprocfs_rd_uuid(char* page, char **start, off_t off, int count,
175                     int *eof, void *data)
176 {
177         struct obd_device* dev = (struct obd_device*)data;
178
179         LASSERT(dev != NULL);
180         *eof = 1;
181         return snprintf(page, count, "%s\n", dev->obd_uuid.uuid);
182 }
183
184 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
185                     int *eof, void *data)
186 {
187         struct obd_device* dev = (struct obd_device *)data;
188
189         LASSERT(dev != NULL);
190         LASSERT(dev->obd_name != NULL);
191         *eof = 1;
192         return snprintf(page, count, "%s\n", dev->obd_name);
193 }
194
195 int lprocfs_rd_blksize(char* page, char **start, off_t off, int count,
196                        int *eof, struct statfs *sfs)
197 {
198         LASSERT(sfs != NULL);
199         *eof = 1;
200         return snprintf(page, count, "%lu\n", sfs->f_bsize);
201 }
202
203 int lprocfs_rd_kbytestotal(char* page, char **start, off_t off, int count,
204                            int *eof, struct statfs *sfs)
205 {
206         __u32 blk_size;
207         __u64 result;
208
209         LASSERT(sfs != NULL);
210         blk_size = sfs->f_bsize >> 10;
211         result = sfs->f_blocks;
212
213         while (blk_size >>= 1)
214                 result <<= 1;
215
216         *eof = 1;
217         return snprintf(page, count, LPU64"\n", result);
218 }
219
220 int lprocfs_rd_kbytesfree(char* page, char **start, off_t off, int count,
221                           int *eof, struct statfs *sfs)
222 {
223         __u32 blk_size;
224         __u64 result;
225
226         LASSERT(sfs != NULL);
227         blk_size = sfs->f_bsize >> 10;
228         result = sfs->f_bfree;
229
230         while (blk_size >>= 1)
231                 result <<= 1;
232
233         *eof = 1;
234         return snprintf(page, count, LPU64"\n", result);
235 }
236
237 int lprocfs_rd_filestotal(char* page, char **start, off_t off, int count,
238                           int *eof, struct statfs *sfs)
239 {
240         LASSERT(sfs != NULL);
241         *eof = 1;
242         return snprintf(page, count, "%ld\n", sfs->f_files);
243 }
244
245 int lprocfs_rd_filesfree(char* page, char **start, off_t off, int count,
246                          int *eof, struct statfs *sfs)
247 {
248         LASSERT(sfs != NULL);
249         *eof = 1;
250         return snprintf(page, count, "%ld\n", sfs->f_ffree);
251 }
252
253 int lprocfs_rd_filegroups(char* page, char **start, off_t off, int count,
254                           int *eof, struct statfs *sfs)
255 {
256         *eof = 1;
257         return snprintf(page, count, "unimplemented\n");
258 }
259
260 int lprocfs_rd_server_uuid(char* page, char **start, off_t off, int count,
261                            int *eof, void *data)
262 {
263         struct obd_device *obd = (struct obd_device *)data;
264         struct client_obd *cli;
265
266         LASSERT(obd != NULL);
267         cli = &obd->u.cli;
268         *eof = 1;
269         return snprintf(page, count, "%s\n",
270                         cli->cl_import->imp_target_uuid.uuid);
271 }
272
273 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
274                          int *eof,  void *data)
275 {
276         struct obd_device *obd = (struct obd_device*)data;
277         struct ptlrpc_connection *conn;
278
279         LASSERT(obd != NULL);
280         conn = obd->u.cli.cl_import->imp_connection;
281         LASSERT(conn != NULL);
282         *eof = 1;
283         return snprintf(page, count, "%s\n", conn->c_remote_uuid.uuid);
284 }
285
286 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
287                        int *eof, void *data)
288 {
289         struct obd_type* class = (struct obd_type*) data;
290
291         LASSERT(class != NULL);
292         *eof = 1;
293         return snprintf(page, count, "%d\n", class->typ_refcnt);
294 }
295
296 int lprocfs_obd_attach(struct obd_device *dev, struct lprocfs_vars *list)
297 {
298         int rc = 0;
299
300         LASSERT(dev != NULL);
301         LASSERT(dev->obd_type != NULL);
302         LASSERT(dev->obd_type->typ_procroot != NULL);
303
304         dev->obd_proc_entry = lprocfs_register(dev->obd_name,
305                                                dev->obd_type->typ_procroot,
306                                                list, dev);
307         if (IS_ERR(dev->obd_proc_entry)) {
308                 rc = PTR_ERR(dev->obd_proc_entry);
309                 dev->obd_proc_entry = NULL;
310         }
311         return rc;
312 }
313
314 int lprocfs_obd_detach(struct obd_device *dev)
315 {
316         if (dev && dev->obd_proc_entry) {
317                 lprocfs_remove(dev->obd_proc_entry);
318                 dev->obd_proc_entry = NULL;
319         }
320         return 0;
321 }
322
323 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num)
324 {
325         struct lprocfs_stats *stats;
326         struct lprocfs_percpu *percpu;
327         unsigned int percpusize;
328         unsigned int i;
329
330         if (num == 0)
331                 return NULL;
332
333         OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[smp_num_cpus]));
334         if (stats == NULL)
335                 return NULL;
336
337         percpusize = L1_CACHE_ALIGN(offsetof(typeof(*percpu), lp_cntr[num]));
338         stats->ls_percpu_size = smp_num_cpus * percpusize;
339         OBD_ALLOC(stats->ls_percpu[0], stats->ls_percpu_size);
340         if (stats->ls_percpu[0] == NULL) {
341                 OBD_FREE(stats, offsetof(typeof(*stats),
342                                          ls_percpu[smp_num_cpus]));
343                 return NULL;
344         }
345
346         stats->ls_num = num;
347         for (i = 1; i < smp_num_cpus; i++)
348                 stats->ls_percpu[i] = (void *)(stats->ls_percpu[i - 1]) +
349                         percpusize;
350
351         return stats;
352 }
353
354 void lprocfs_free_stats(struct lprocfs_stats *stats)
355 {
356         if (stats->ls_num == 0)
357                 return;
358
359         OBD_FREE(stats->ls_percpu[0], stats->ls_percpu_size);
360         OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[smp_num_cpus]));
361 }
362
363 /* Reset counter under lock */
364 int lprocfs_counter_write(struct file *file, const char *buffer,
365                           unsigned long count, void *data)
366 {
367         /* not supported */
368         return 0;
369 }
370
371 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
372 {
373         struct lprocfs_stats *stats = p->private;
374         /* return 1st cpu location */
375         return (*pos >= stats->ls_num) ? NULL :
376                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
377 }
378
379 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
380 {
381 }
382
383 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
384 {
385         struct lprocfs_stats *stats = p->private;
386         ++*pos;
387         return (*pos >= stats->ls_num) ? NULL :
388                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
389 }
390
391 /* seq file export of one lprocfs counter */
392 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
393 {
394        struct lprocfs_stats *stats = p->private;
395        struct lprocfs_counter  *cntr = v;
396        struct lprocfs_counter  t, ret = { .lc_min = ~(__u64)0 };
397        int i, idx, rc;
398
399        if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
400                struct timeval now;
401                do_gettimeofday(&now);
402                rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
403                                "snapshot_time", now.tv_sec, now.tv_usec);
404                if (rc < 0)
405                        return rc;
406        }
407        idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
408
409        for (i = 0; i < smp_num_cpus; i++) {
410                struct lprocfs_counter *percpu_cntr =
411                        &(stats->ls_percpu[i])->lp_cntr[idx];
412                int centry;
413                do {
414                         centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
415                         t.lc_count = percpu_cntr->lc_count;
416                         t.lc_sum = percpu_cntr->lc_sum;
417                         t.lc_min = percpu_cntr->lc_min;
418                         t.lc_max = percpu_cntr->lc_max;
419                         t.lc_sumsquare = percpu_cntr->lc_sumsquare;
420                } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
421                         centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
422                ret.lc_count += t.lc_count;
423                ret.lc_sum += t.lc_sum;
424                if (t.lc_min < ret.lc_min)
425                        ret.lc_min = t.lc_min;
426                if (t.lc_max > ret.lc_max)
427                        ret.lc_max = t.lc_max;
428                ret.lc_sumsquare += t.lc_sumsquare;
429        }
430
431        rc = seq_printf(p, "%-25s "LPU64" samples [%s]", cntr->lc_name,
432                        ret.lc_count, cntr->lc_units);
433        if (rc < 0)
434                goto out;
435
436        if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
437                rc = seq_printf(p, " "LPU64" "LPU64" "LPU64,
438                                ret.lc_min, ret.lc_max, ret.lc_sum);
439                if (rc < 0)
440                        goto out;
441                if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
442                        rc = seq_printf(p, " "LPU64, ret.lc_sumsquare);
443                if (rc < 0)
444                        goto out;
445        }
446        rc = seq_printf(p, "\n");
447  out:
448        return (rc < 0) ? rc : 0;
449 }
450
451 struct seq_operations lprocfs_stats_seq_sops = {
452         .start = lprocfs_stats_seq_start,
453         .stop = lprocfs_stats_seq_stop,
454         .next = lprocfs_stats_seq_next,
455         .show = lprocfs_stats_seq_show,
456 };
457
458 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
459 {
460         struct proc_dir_entry *dp = inode->u.generic_ip;
461         struct seq_file *seq;
462         int rc;
463
464         rc = seq_open(file, &lprocfs_stats_seq_sops);
465         if (rc)
466                 return rc;
467         seq = file->private_data;
468         seq->private = dp->data;
469         return 0;
470 }
471
472 struct file_operations lprocfs_stats_seq_fops = {
473         .open    = lprocfs_stats_seq_open,
474         .read    = seq_read,
475         .llseek  = seq_lseek,
476         .release = seq_release,
477 };
478
479 int lprocfs_register_stats(struct proc_dir_entry *root, const char* name,
480                            struct lprocfs_stats *stats)
481 {
482         struct proc_dir_entry *entry;
483         LASSERT(root != NULL);
484
485         entry = create_proc_entry(name, 0444, root);
486         if (entry == NULL)
487                 return -ENOMEM;
488         entry->proc_fops = &lprocfs_stats_seq_fops;
489         entry->data = (void *)stats;
490         entry->write_proc = lprocfs_counter_write;
491         return 0;
492 }
493
494 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
495                           unsigned conf, const char *name, const char *units)
496 {
497         struct lprocfs_counter *c;
498         int i;
499
500         LASSERT(stats != NULL);
501         for (i = 0; i < smp_num_cpus; i++) {
502                 c = &(stats->ls_percpu[i]->lp_cntr[index]);
503                 c->lc_config = conf;
504                 c->lc_min = ~(__u64)0;
505                 c->lc_name = name;
506                 c->lc_units = units;
507         }
508 }
509 EXPORT_SYMBOL(lprocfs_counter_init);
510
511 #define LPROCFS_OBD_OP_INIT(base, stats, op)                               \
512 do {                                                                       \
513         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);              \
514         LASSERT(coffset < stats->ls_num);                                     \
515         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");              \
516 } while (0)
517
518 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
519 {
520         struct lprocfs_stats *stats;
521         unsigned int num_stats;
522         int rc, i;
523
524         LASSERT(obd->obd_stats == NULL);
525         LASSERT(obd->obd_proc_entry != NULL);
526         LASSERT(obd->obd_cntr_base == 0);
527
528         num_stats = 1 + OBD_COUNTER_OFFSET(destroy_export) +
529                 num_private_stats;
530         stats = lprocfs_alloc_stats(num_stats);
531         if (!stats)
532                 return -ENOMEM;
533
534         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
535         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
536         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info);
537         LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
538         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
539         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
540         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
541         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
542         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
543         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
544         LPROCFS_OBD_OP_INIT(num_private_stats, stats, syncfs);
545         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
546         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
547         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
548         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
549         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
550         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
551         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
552         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
553         LPROCFS_OBD_OP_INIT(num_private_stats, stats, open);
554         LPROCFS_OBD_OP_INIT(num_private_stats, stats, close);
555         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
556         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
557         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
558         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
559         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
560         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
561         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
562         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
563         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
564         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
565         LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
566         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
567         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
568         LPROCFS_OBD_OP_INIT(num_private_stats, stats, san_preprw);
569         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
570
571         for (i = num_private_stats; i < num_stats; i++) {
572                 /* If this assertion failed, it is likely that an obd
573                  * operation was added to struct obd_ops in
574                  * <linux/obd.h>, and that the corresponding line item
575                  * LPROCFS_OBD_OP_INIT(.., .., opname)
576                  * is missing from the list above. */
577                 LASSERT(&(stats->ls_percpu[0])->lp_cntr[i].lc_name != NULL);
578         }
579         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
580         if (rc < 0) {
581                 lprocfs_free_stats(stats);
582         } else {
583                 obd->obd_stats  = stats;
584                 obd->obd_cntr_base = num_private_stats;
585         }
586         return rc;
587 }
588
589 void lprocfs_free_obd_stats(struct obd_device *obd)
590 {
591         struct lprocfs_stats *stats = obd->obd_stats;
592
593         if (stats != NULL) {
594                 obd->obd_stats = NULL;
595                 lprocfs_free_stats(stats);
596         }
597 }
598
599 #endif /* LPROCFS*/
600
601 EXPORT_SYMBOL(lprocfs_register);
602 EXPORT_SYMBOL(lprocfs_srch);
603 EXPORT_SYMBOL(lprocfs_remove);
604 EXPORT_SYMBOL(lprocfs_add_vars);
605 EXPORT_SYMBOL(lprocfs_obd_attach);
606 EXPORT_SYMBOL(lprocfs_obd_detach);
607 EXPORT_SYMBOL(lprocfs_alloc_stats);
608 EXPORT_SYMBOL(lprocfs_free_stats);
609 EXPORT_SYMBOL(lprocfs_register_stats);
610 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
611 EXPORT_SYMBOL(lprocfs_free_obd_stats);
612
613 EXPORT_SYMBOL(lprocfs_rd_u64);
614 EXPORT_SYMBOL(lprocfs_rd_uuid);
615 EXPORT_SYMBOL(lprocfs_rd_name);
616 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
617 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
618 EXPORT_SYMBOL(lprocfs_rd_numrefs);
619
620 EXPORT_SYMBOL(lprocfs_rd_blksize);
621 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
622 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
623 EXPORT_SYMBOL(lprocfs_rd_filestotal);
624 EXPORT_SYMBOL(lprocfs_rd_filesfree);
625 EXPORT_SYMBOL(lprocfs_rd_filegroups);