Whamcloud - gitweb
* 1st attempt to prevent duplicate devices being started.
[fs/lustre-release.git] / lustre / obdclass / lprocfs.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2002 Intel Corporation
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
8  *   Lustre is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Lustre is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Lustre; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 /*
23  * Author: Hariharan Thantry
24  * File Name: lprocfs.c
25  *
26  * During initialization (of lustre), the following directory materializes
27  *          /proc/lustre
28  * When the first OBD device of a class is created (due to insmod)
29  * the directory
30  *         /proc/lustre/devices/<device-class> is created.
31  * When an instance of a device is created (during attach) the
32  * directory entry for that instance along with the variables for
33  * that entry gets created. These variables could be counters, string
34  * variables etc.
35  * Each API further describes the functionality offered.
36  *
37  */
38
39 #define EXPORT_SYMTAB
40 #include <linux/config.h>
41 #include <linux/module.h>
42 #include <linux/version.h>
43 #include <linux/proc_fs.h>
44 #include <linux/slab.h>
45 #include <linux/types.h>
46 #include <linux/string.h>
47
48 #define DEBUG_SUBSYSTEM S_CLASS
49 #define MAX_STRING_SIZE 100
50
51
52 #include <linux/obd_support.h>
53 #include <linux/obd_class.h>
54 #include <linux/lprocfs.h>
55 #include <linux/string.h>
56 #include <linux/lustre_lib.h>
57
58 #ifdef LPROCFS_EXISTS
59
60 #define DEFAULT_MODE 0644
61 /*
62  * Tokenizer array. Change this array to include special
63  * characters for string tokenizing
64  */
65 char tok[] = {'/', (char)0};
66 char enum_char = '_';
67 /*
68  * Escape character. To be used in directories that
69  * should not have any counter/variable entries under
70  * them. Used for hierarchical directories
71  */
72
73 char escape_char = '%';
74
75 /*
76  * Externs
77  */
78 extern struct proc_dir_entry proc_root; /* Defined in proc/root.c */
79
80
81 /*
82  * Globals
83  */
84
85 static struct proc_dir_entry *proc_lustre_root = 0;
86 static struct proc_dir_entry *proc_lustre_dev_root = 0;
87
88 /* struct lustre_lock proc_lustre_lock; */
89 /* static struct proc_dir_entry *proc_lustre_conn_root = 0; */
90 char *testStr = "General..";
91
92 /*
93  * Link the namespace with the internal array indices for
94  * each device class, only if proc lustre is defined
95  */
96
97 struct namespace_index dir_mdc_index[] = {
98         LPROCFS_DIR_INDEX(mdc, mgmt_setup),
99         LPROCFS_DIR_INDEX(mdc, mgmt_cleanup),
100         LPROCFS_DIR_INDEX(mdc, mgmt_connect),
101         LPROCFS_DIR_INDEX(mdc, mgmt_disconnect),
102         LPROCFS_DIR_INDEX(mdc, reint),
103         LPROCFS_DIR_INDEX(mdc, getstatus),
104         LPROCFS_DIR_INDEX(mdc, getattr),
105         LPROCFS_DIR_INDEX(mdc, setattr),
106         LPROCFS_DIR_INDEX(mdc, open),
107         LPROCFS_DIR_INDEX(mdc, readpage),
108         LPROCFS_DIR_INDEX(mdc, create),
109         LPROCFS_DIR_INDEX(mdc, unlink),
110         LPROCFS_DIR_INDEX(mdc, link),
111         LPROCFS_DIR_INDEX(mdc, rename),
112 };
113
114 struct namespace_index dir_mds_index[] = {
115         LPROCFS_DIR_INDEX(mds, mgmt_setup),
116         LPROCFS_DIR_INDEX(mds, mgmt_cleanup),
117         LPROCFS_DIR_INDEX(mds, mgmt_connect),
118         LPROCFS_DIR_INDEX(mds, mgmt_disconnect),
119         LPROCFS_DIR_INDEX(mds, getstatus),
120         LPROCFS_DIR_INDEX(mds, connect),
121         LPROCFS_DIR_INDEX(mds, disconnect_callback),
122         LPROCFS_DIR_INDEX(mds, getattr),
123         LPROCFS_DIR_INDEX(mds, readpage),
124         LPROCFS_DIR_INDEX(mds, open),
125         LPROCFS_DIR_INDEX(mds, close),
126         LPROCFS_DIR_INDEX(mds, create),
127         LPROCFS_DIR_INDEX(mds, unlink),
128         LPROCFS_DIR_INDEX(mds, link),
129         LPROCFS_DIR_INDEX(mds, rename),
130         LPROCFS_DIR_INDEX(mds, reint_summary),
131         LPROCFS_DIR_INDEX(mds, reint_setattr),
132         LPROCFS_DIR_INDEX(mds, reint_create),
133         LPROCFS_DIR_INDEX(mds, reint_unlink),
134         LPROCFS_DIR_INDEX(mds, reint_link),
135         LPROCFS_DIR_INDEX(mds, reint_rename),
136         LPROCFS_DIR_INDEX(mds, reint_recreate),
137 };
138
139 struct namespace_index dir_mdt_index[] = {
140         LPROCFS_DIR_INDEX(mdt, mgmt_setup),
141         LPROCFS_DIR_INDEX(mdt, mgmt_cleanup),
142         LPROCFS_DIR_INDEX(mdt, mgmt_connect),
143         LPROCFS_DIR_INDEX(mdt, mgmt_disconnect),
144 };
145
146 struct namespace_index dir_osc_index[] = {
147         LPROCFS_DIR_INDEX(osc, mgmt_setup),
148         LPROCFS_DIR_INDEX(osc, mgmt_cleanup),
149         LPROCFS_DIR_INDEX(osc, mgmt_connect),
150         LPROCFS_DIR_INDEX(osc, mgmt_disconnect),
151         LPROCFS_DIR_INDEX(osc, create),
152         LPROCFS_DIR_INDEX(osc, destroy),
153         LPROCFS_DIR_INDEX(osc, getattr),
154         LPROCFS_DIR_INDEX(osc, setattr),
155         LPROCFS_DIR_INDEX(osc, open),
156         LPROCFS_DIR_INDEX(osc, close),
157         LPROCFS_DIR_INDEX(osc, brw),
158         LPROCFS_DIR_INDEX(osc, punch),
159         LPROCFS_DIR_INDEX(osc, summary),
160         LPROCFS_DIR_INDEX(osc, cancel),
161 };
162
163 struct namespace_index dir_ost_index[] = {
164         LPROCFS_DIR_INDEX(ost, mgmt_setup),
165         LPROCFS_DIR_INDEX(ost, mgmt_cleanup),
166         LPROCFS_DIR_INDEX(ost, mgmt_connect),
167         LPROCFS_DIR_INDEX(ost, mgmt_disconnect),
168         LPROCFS_DIR_INDEX(ost, create),
169         LPROCFS_DIR_INDEX(ost, destroy),
170         LPROCFS_DIR_INDEX(ost, getattr),
171         LPROCFS_DIR_INDEX(ost, setattr),
172         LPROCFS_DIR_INDEX(ost, open),
173         LPROCFS_DIR_INDEX(ost, close),
174         LPROCFS_DIR_INDEX(ost, brw),
175         LPROCFS_DIR_INDEX(ost, punch),
176         LPROCFS_DIR_INDEX(ost, summary),
177         LPROCFS_DIR_INDEX(ost, cancel),
178         LPROCFS_DIR_INDEX(ost, getinfo),
179 };
180
181 struct namespace_index dir_lov_index[] = {
182         LPROCFS_DIR_INDEX(lov, mgmt_setup),
183         LPROCFS_DIR_INDEX(lov, mgmt_cleanup),
184         LPROCFS_DIR_INDEX(lov, mgmt_connect),
185         LPROCFS_DIR_INDEX(lov, mgmt_disconnect),
186         LPROCFS_DIR_INDEX(lov, create),
187         LPROCFS_DIR_INDEX(lov, destroy),
188         LPROCFS_DIR_INDEX(lov, getattr),
189         LPROCFS_DIR_INDEX(lov, setattr),
190         LPROCFS_DIR_INDEX(lov, open),
191         LPROCFS_DIR_INDEX(lov, close),
192         LPROCFS_DIR_INDEX(lov, brw),
193         LPROCFS_DIR_INDEX(lov, punch),
194         LPROCFS_DIR_INDEX(lov, summary),
195         LPROCFS_DIR_INDEX(lov, cancel),
196         LPROCFS_DIR_INDEX(lov, getinfo),
197 };
198
199 struct namespace_index dir_obdfilter_index[] = {
200         LPROCFS_DIR_INDEX(obdfilter, mgmt_setup),
201         LPROCFS_DIR_INDEX(obdfilter, mgmt_cleanup),
202         LPROCFS_DIR_INDEX(obdfilter, mgmt_connect),
203         LPROCFS_DIR_INDEX(obdfilter, mgmt_disconnect),
204         LPROCFS_DIR_INDEX(obdfilter, create),
205         LPROCFS_DIR_INDEX(obdfilter, destroy),
206         LPROCFS_DIR_INDEX(obdfilter, getattr),
207         LPROCFS_DIR_INDEX(obdfilter, setattr),
208         LPROCFS_DIR_INDEX(obdfilter, open),
209         LPROCFS_DIR_INDEX(obdfilter, close),
210         LPROCFS_DIR_INDEX(obdfilter, brw),
211         LPROCFS_DIR_INDEX(obdfilter, punch),
212         LPROCFS_DIR_INDEX(obdfilter, summary),
213         LPROCFS_DIR_INDEX(obdfilter, cancel),
214         LPROCFS_DIR_INDEX(obdfilter, getinfo),
215 };
216
217 struct namespace_index dir_ldlm_index[] = {
218         LPROCFS_DIR_INDEX(ldlm, mgmt_setup),
219         LPROCFS_DIR_INDEX(ldlm, mgmt_cleanup),
220         LPROCFS_DIR_INDEX(ldlm, mgmt_connect),
221         LPROCFS_DIR_INDEX(ldlm, mgmt_disconnect),
222         LPROCFS_DIR_INDEX(ldlm, locks_enqueus),
223         LPROCFS_DIR_INDEX(ldlm, locks_cancels),
224         LPROCFS_DIR_INDEX(ldlm, locks_converts),
225         LPROCFS_DIR_INDEX(ldlm, locks_matches),
226 };
227
228 struct namespace_index dir_ptlrpc_index[] = {
229         LPROCFS_DIR_INDEX(ptlrpc, mgmt_setup),
230         LPROCFS_DIR_INDEX(ptlrpc, mgmt_cleanup),
231         LPROCFS_DIR_INDEX(ptlrpc, mgmt_connect),
232         LPROCFS_DIR_INDEX(ptlrpc, mgmt_disconnect),
233         LPROCFS_DIR_INDEX(ptlrpc, counters),
234 };
235
236 struct namespace_index prof_mdc_index[] = {
237         LPROCFS_CNTR_INDEX(mdc, min_time),
238         LPROCFS_CNTR_INDEX(mdc, max_time),
239         LPROCFS_CNTR_INDEX(mdc, sum_time),
240         LPROCFS_CNTR_INDEX(mdc, num_ops),
241 };
242
243 struct namespace_index prof_mds_index[]= {
244         LPROCFS_CNTR_INDEX(mds, min_time),
245         LPROCFS_CNTR_INDEX(mds, max_time),
246         LPROCFS_CNTR_INDEX(mds, sum_time),
247         LPROCFS_CNTR_INDEX(mds, num_ops),
248 };
249
250 struct namespace_index prof_mdt_index[]= {
251         LPROCFS_CNTR_INDEX(mds, min_time),
252         LPROCFS_CNTR_INDEX(mds, max_time),
253         LPROCFS_CNTR_INDEX(mds, sum_time),
254         LPROCFS_CNTR_INDEX(mds, num_ops),
255 };
256
257 struct namespace_index prof_osc_index[]= {
258         LPROCFS_CNTR_INDEX(osc, min_time),
259         LPROCFS_CNTR_INDEX(osc, max_time),
260         LPROCFS_CNTR_INDEX(osc, sum_time),
261         LPROCFS_CNTR_INDEX(osc, num_ops),
262 };
263
264 struct namespace_index prof_ost_index[]= {
265         LPROCFS_CNTR_INDEX(ost, min_time),
266         LPROCFS_CNTR_INDEX(ost, max_time),
267         LPROCFS_CNTR_INDEX(ost, sum_time),
268         LPROCFS_CNTR_INDEX(ost, num_ops),
269 };
270
271 struct namespace_index prof_lov_index[]= {
272         LPROCFS_CNTR_INDEX(lov, min_time),
273         LPROCFS_CNTR_INDEX(lov, max_time),
274         LPROCFS_CNTR_INDEX(lov, sum_time),
275         LPROCFS_CNTR_INDEX(lov, num_ops),
276 };
277
278 struct namespace_index prof_obdfilter_index[]= {
279         LPROCFS_CNTR_INDEX(obdfilter, min_time),
280         LPROCFS_CNTR_INDEX(obdfilter, max_time),
281         LPROCFS_CNTR_INDEX(obdfilter, sum_time),
282         LPROCFS_CNTR_INDEX(obdfilter, num_ops),
283 };
284
285 struct namespace_index prof_ldlm_index[] = {
286         LPROCFS_CNTR_INDEX(ldlm, min_time),
287         LPROCFS_CNTR_INDEX(ldlm, max_time),
288         LPROCFS_CNTR_INDEX(ldlm, sum_time),
289         LPROCFS_CNTR_INDEX(ldlm, num_ops),
290         LPROCFS_CNTR_INDEX(ldlm, num_total),
291         LPROCFS_CNTR_INDEX(ldlm, num_zerolatency),
292         LPROCFS_CNTR_INDEX(ldlm, num_zerolatency_inflight),
293         LPROCFS_CNTR_INDEX(ldlm, num_zerolatency_done),
294         LPROCFS_CNTR_INDEX(ldlm, nonzero_mintime),
295         LPROCFS_CNTR_INDEX(ldlm, nonzero_maxtime),
296         LPROCFS_CNTR_INDEX(ldlm, nonzero_sumtime),
297 };
298
299 struct namespace_index prof_ptlrpc_index[] = {
300         LPROCFS_CNTR_INDEX(ptlrpc, min_time),
301         LPROCFS_CNTR_INDEX(ptlrpc, max_time),
302         LPROCFS_CNTR_INDEX(ptlrpc, sum_time),
303         LPROCFS_CNTR_INDEX(ptlrpc, num_ops),
304         LPROCFS_CNTR_INDEX(ptlrpc, msgs_alloc),
305         LPROCFS_CNTR_INDEX(ptlrpc, msgs_max),
306         LPROCFS_CNTR_INDEX(ptlrpc, recv_count),
307         LPROCFS_CNTR_INDEX(ptlrpc, recv_length),
308         LPROCFS_CNTR_INDEX(ptlrpc, send_count),
309         LPROCFS_CNTR_INDEX(ptlrpc, send_length),
310         LPROCFS_CNTR_INDEX(ptlrpc, portal_kmemory),
311 };
312
313 /*
314  * Group the device class name, its directory hierarchy and
315  * leaf nodes together
316  */
317
318 struct groupspace_index class_index[] = {
319         LPROCFS_GROUP_CREATE(mdc),
320         LPROCFS_GROUP_CREATE(mds),
321         LPROCFS_GROUP_CREATE(mdt),
322         LPROCFS_GROUP_CREATE(osc),
323         LPROCFS_GROUP_CREATE(ost),
324         LPROCFS_GROUP_CREATE(lov),
325         LPROCFS_GROUP_CREATE(obdfilter),
326         LPROCFS_GROUP_CREATE(ldlm),
327         LPROCFS_GROUP_CREATE(ptlrpc),
328 };
329
330
331 /*
332  *  API implementations
333  */
334
335 /*
336  * lprocfs_reg_dev: Registers an instance of the OBD device in the
337  *                       proc hierarchy
338  */
339
340 int lprocfs_reg_dev(struct obd_device* device, lprocfs_group_t* namespace,
341                     unsigned int cnt_struct_size)
342 {
343         unsigned int num_directories = 0;
344         int class_array_index = 0;
345         int retval = 0;
346         struct proc_dir_entry* this_dev_root=0;
347         unsigned int i = 0, j = 0;
348
349         /* Obtain this device root */
350         this_dev_root = lprocfs_mkinitdir(device);
351         if (this_dev_root == 0) {
352                 CERROR("Could not create initial directory");
353                 return LPROCFS_FAILURE;
354         }
355
356         /* Obtain the class-array index */
357         class_array_index = lprocfs_getclass_idx(class_index,
358                                                  device->obd_type->typ_name);
359
360         if (class_array_index == LPROCFS_FAILURE) {
361                 CERROR("Could not find class for %s\n",
362                        device->obd_type->typ_name);
363                 return LPROCFS_FAILURE;
364         }
365
366         /* Create the directory namespace */
367         retval = lprocfs_create_dir_namespace(this_dev_root, namespace,
368                                               &num_directories);
369         if (retval == LPROCFS_FAILURE) {
370                 CERROR("!!Could not create proc directory structure !!\n");
371                 return LPROCFS_FAILURE;
372         }
373
374         /* Allocate memory managed by LProcFS for the device. */
375         if (cnt_struct_size != 0) {
376                 OBD_ALLOC(device->counters, num_directories*cnt_struct_size);
377                 device->cntr_mem_size = num_directories*cnt_struct_size;
378         }
379
380         /*
381          * Iterate the proc-dir-namespace, obtain corresponding
382          * directory(attribute)
383          * entries. Create the proc-counters from namespace, link them into
384          * dev counters
385          */
386         retval=lprocfs_link_dir_counters(device, this_dev_root, namespace,
387                                          cnt_struct_size, class_array_index);
388
389         if (retval == LPROCFS_FAILURE) {
390                 CERROR("!! Could not link proc counters to device !!");
391                 return LPROCFS_FAILURE;
392         }
393
394         /*
395          * Test code: This goes into individual modules. strcmp is
396          * unnecessary, since device knows its class. To see the values
397          * from the user space, do a cat on the respective variable
398          */
399         if (!(strcmp(device->obd_type->typ_name, "mds"))) {
400                 DEV_PROF_START(mds, device, gen, mgmt_setup);
401
402                 for (i = 0; i < 100; i++)
403                         for (j = 0; j < 100; j++)
404                                 continue;
405
406                 DEV_PROF_END(mds, device, gen, mgmt_setup);
407
408                 DEV_PROF_START(mds, device, gen, mgmt_setup);
409
410                 for (i = 0; i < 1000; i++)
411                         for (j = 0; j < 1000; j++)
412                                 continue;
413
414                 DEV_PROF_END(mds, device, gen, mgmt_setup);
415
416
417                 DEV_PROF_START(mds, device, gen, open);
418                 for (i = 0; i < 50; i++) {
419                         DEV_PROF_START(mds, device, gen, close);
420                         for (j = 0; j < 2000; j++)
421                                 continue;
422                         DEV_PROF_END(mds, device, gen, close);
423                 }
424                 DEV_PROF_END(mds, device, gen, open);
425         }
426
427         if (!(strcmp(device->obd_type->typ_name, "ldlm"))) {
428                 DEV_PROF_START(ldlm, device, ldlm, mgmt_connect);
429                 for (i = 0; i < 200; i++) {
430                         DEV_PROF_START(ldlm, device, ldlm, mgmt_disconnect);
431                         for (j = 0; j < 2000; j++)
432                                 continue;
433                         DEV_PROF_END(ldlm, device, ldlm, mgmt_disconnect);
434                 }
435                 DEV_PROF_END(ldlm, device, ldlm, mgmt_connect);
436         }
437
438         return LPROCFS_SUCCESS;
439 }
440
441 int lprocfs_link_dir_counters(struct obd_device* device,
442                               struct proc_dir_entry* root,
443                               lprocfs_group_t* namespace,
444                               unsigned int sz,
445                               unsigned int cl_idx)
446 {
447         struct proc_dir_entry* dir_root=0;
448         lprocfs_group_t* temp;
449         lprocfs_vars_t* fn_ctr;
450         struct namespace_index* cntr_names;
451         unsigned int i = 0;
452         unsigned int j = 0;
453         unsigned int k = 0;
454         unsigned int escape = 0;
455         int dir_idx = -1;
456         int cnt_idx = -1;
457
458         while(1) {
459                 temp = &namespace[i];
460                 dir_idx = -1;
461                 if (temp->count_func_namespace == 0)
462                         break;
463
464                 while ((temp->dir_namespace)[j] != 0) {
465                         dir_root = lprocfs_add_dir(root,
466                                                    (temp->dir_namespace)[j],
467                                                    (const char*)tok, &escape);
468                         if (escape) {
469                                 j++;
470                                 continue;
471                         }
472
473                         dir_idx = lprocfs_get_idx(class_index[cl_idx].directory,
474                                                   (temp->dir_namespace)[j]);
475                         while(1) {
476                                 cnt_idx = -1;
477                                 fn_ctr = &((temp->count_func_namespace)[k]);
478                                 if (fn_ctr->read_fptr == 0)
479                                         break;
480                                 cntr_names = class_index[cl_idx].counters;
481                                 cnt_idx = lprocfs_get_idx(cntr_names,
482                                                           fn_ctr->name);
483
484                                 if (lprocfs_add_var(device, dir_root, fn_ctr,
485                                                    dir_idx, cnt_idx, sz,
486                                                    temp->prof_type) ==
487                                    LPROCFS_FAILURE){
488                                         CERROR("Could not create leaf node!");
489                                         return LPROCFS_FAILURE;
490
491                                 }
492
493                                 k++;
494                         }
495
496                         k=0;
497                         j++;
498
499                 }
500                 k=0;
501                 j=0;
502                 i++;
503         }
504
505         return LPROCFS_SUCCESS;
506 }
507
508 int lprocfs_create_dir_namespace(struct proc_dir_entry* root,
509                                  lprocfs_group_t* namespace,
510                                  unsigned int *num_dirs)
511 {
512         unsigned int i = 0;
513         unsigned int j = 0;
514         struct proc_dir_entry* dir_root=0;
515         lprocfs_group_t* temp;
516         unsigned int escape = 0;
517
518         while (1) {
519                 temp = &namespace[i];
520                 if (temp->count_func_namespace == 0)
521                         break;
522                 while ((temp->dir_namespace)[j] != 0){
523                         dir_root = lprocfs_add_dir(root,
524                                                    (temp->dir_namespace)[j],
525                                                    (const char*)tok, &escape);
526                         if (dir_root == 0) {
527                                 CERROR("!! Could not create dir  %s !! \n",
528                                        (temp->dir_namespace)[j]);
529                                 return LPROCFS_FAILURE;
530                         }
531                         if (temp->prof_type != e_specific && !escape)
532                                 (*num_dirs)++;
533                         j++;
534                 }
535                 j = 0;
536                 i++;
537         }
538
539         return LPROCFS_SUCCESS;
540 }
541
542
543 int lprocfs_getclass_idx(struct groupspace_index* group, const char* classname)
544 {
545         unsigned int idx = 0;
546
547         while (group[idx].name != NULL) {
548                 if (!strcmp(group[idx].name, classname))
549                         return idx;
550                 idx++;
551         }
552
553         return LPROCFS_FAILURE;
554 }
555
556 struct proc_dir_entry* lprocfs_mkinitdir(struct obd_device* device)
557 {
558         struct proc_dir_entry* this_dev_root = 0;
559         struct proc_dir_entry* temp_proc = 0;
560
561         /*
562          * First check if /proc/lustre exits. If it does not,
563          * instantiate the same and the devices directory
564          */
565         if (!proc_lustre_root) {
566                 proc_lustre_root = lprocfs_mkdir("lustre", &proc_root);
567                 if (!proc_lustre_root) {
568                         CERROR(" !! Cannot create /proc/lustre !! \n");
569                         return 0;
570                 }
571                 proc_lustre_dev_root =
572                         lprocfs_mkdir("devices", proc_lustre_root);
573
574                 if (!proc_lustre_dev_root) {
575                         CERROR(" !! Cannot create /proc/lustre/devices !! \n");
576                         return 0;
577                 }
578         }
579
580         /*
581          * Check if this is the first instance for a device of
582          * this class in the lprocfs hierarchy.
583          */
584         temp_proc = lprocfs_srch(proc_lustre_dev_root,
585                                  device->obd_type->typ_name);
586
587         if (!temp_proc) {
588                 temp_proc = lprocfs_mkdir(device->obd_type->typ_name,
589                                           proc_lustre_dev_root);
590                 if (!temp_proc) {
591                         CERROR("! Proc dir for device class %s !!\n",
592                                device->obd_type->typ_name);
593                         return 0;
594                 }
595         }
596
597         /* Next create the proc_dir_entry for this instance */
598         this_dev_root = lprocfs_mkdir(device->obd_name, temp_proc);
599         if (!this_dev_root) {
600                 CERROR("!Can't create proc entry for instance %s !! \n",
601                        device->obd_name);
602                 return 0;
603         }
604
605         return this_dev_root;
606 }
607
608
609 int lprocfs_get_idx(struct namespace_index* class, const char* dir_name)
610 {
611         unsigned int index = 0;
612         char temp_string[MAX_STRING_SIZE];
613
614         /* First replace the string tokenizer with enum character */
615         memset(temp_string, 0, MAX_STRING_SIZE);
616         while (dir_name[index]!='\0' && index < MAX_STRING_SIZE) {
617                 if (dir_name[index] != tok[0])
618                         temp_string[index] = dir_name[index];
619                 else
620                         temp_string[index] = enum_char;
621                 index++;
622         }
623         temp_string[index] = '\0';
624
625         index = 0;
626         while (class[index].name) {
627                 if (!strcmp(class[index].name, temp_string))
628                         return index;
629                 index++;
630         }
631
632         CDEBUG(D_OTHER, "No profiling for %s\n", temp_string);
633         return -1;
634 }
635
636 struct proc_dir_entry* lprocfs_mkdir(const char* dname,
637                                      struct proc_dir_entry *parent)
638 {
639         struct proc_dir_entry *child_dir_entry;
640
641         child_dir_entry = proc_mkdir(dname, parent);
642
643         if (!child_dir_entry)
644                 CERROR("lustre: failed to create /proc entry %s\n", dname);
645
646         return child_dir_entry;
647 }
648
649 /*
650  * Create the variable struct entry for /proc. This will also
651  * register the read/write function pointers with
652  * /proc/lustre.
653  * Returns non-zero on success, zero on failure
654  */
655 unsigned int lprocfs_add_var(struct obd_device* device,
656                              struct proc_dir_entry* root,
657                              lprocfs_vars_t* variable, int dir_idx, int cnt_idx,
658                              unsigned int sz, lprofilers_e type)
659 {
660         struct proc_dir_entry* new_proc_entry;
661         __u64* temp;
662         unsigned int actual_idx;
663         unsigned int blk_size;
664
665         new_proc_entry = create_proc_entry(variable->name, DEFAULT_MODE, root);
666         if (!new_proc_entry)
667                 return LPROCFS_FAILURE;
668
669         new_proc_entry->read_proc = variable->read_fptr;
670         new_proc_entry->write_proc = variable->write_fptr;
671
672         switch(type){
673         case e_generic:
674                 if (device->counters) {
675                         if (dir_idx != -1 && cnt_idx != -1) {
676                                 temp = (__u64*)device->counters;
677                                 blk_size = ((sz) / (sizeof(__u64)));
678                                 actual_idx = (dir_idx*blk_size) + cnt_idx;
679                                 temp += actual_idx;
680                                 new_proc_entry->data = (__u64*)temp;
681                         }
682                 }
683                 break;
684         case e_specific:
685                  new_proc_entry->data = device;
686                  break;
687         }
688
689         return LPROCFS_SUCCESS;
690 }
691
692
693 /*
694  * Tokenize name, based on tok and end-of-string. Create and return the
695  * new directory entry. Set escape variable if the directory name contained
696  * the escaping character (#)
697  */
698
699 struct proc_dir_entry* lprocfs_add_dir(struct proc_dir_entry *root,
700                                        const char* string,
701                                        const char* tok,
702                                        unsigned int* escape)
703 {
704         struct proc_dir_entry* new_root = 0;
705         struct proc_dir_entry* temp_entry = 0;
706         struct proc_dir_entry* new_entry = 0;
707         char temp_string[MAX_STRING_SIZE];
708         char* my_str;
709         char* mover_str;
710
711         /*
712          * Remove trailing escaping character
713          */
714         memset(temp_string, 0, MAX_STRING_SIZE);
715         if (strlen(string) >= MAX_STRING_SIZE) {
716                 CERROR("Directory namespace too long");
717                 return 0;
718         }
719
720         if (strchr(string, escape_char)) {
721                 *escape = 1;
722                 strncpy(temp_string,string,strlen(string) - 1);
723                 temp_string[strlen(string)] = '\0';
724         } else {
725                 *escape = 0;
726                 strcpy(temp_string, string);
727                 temp_string[strlen(string) + 1] = '\0';
728         }
729
730         new_root=root;
731
732         /* Using strsep() instead */
733         mover_str=temp_string;
734         while ((my_str = strsep(&mover_str, tok))) {
735                 if(!*my_str)
736                         continue;
737                 temp_entry = lprocfs_srch(new_root, my_str);
738                 if (temp_entry == 0) {
739                         new_entry = lprocfs_mkdir(my_str, new_root);
740                         if (new_entry == 0) {
741                                 CERROR("! Did not create new dir %s !!\n",
742                                        my_str);
743                                 return 0;
744                         }
745                         return new_entry;
746                 }
747                 new_root = temp_entry;
748         }
749
750         return new_root;
751 }
752
753 struct proc_dir_entry* lprocfs_srch(struct proc_dir_entry* head,
754                                     const char* name)
755 {
756         struct proc_dir_entry* temp;
757
758         if (!head)
759                 return 0;
760         temp = head->subdir;
761         while (temp != NULL) {
762                 if (!strcmp(temp->name, name))
763                         return temp;
764                 temp = temp->next;
765         }
766
767         return 0;
768 }
769
770 #warning FIXME: recursive code is VERY bad in the kernel because of stack limit
771 struct proc_dir_entry* lprocfs_bfs_srch(struct proc_dir_entry* root,
772                                         const char* name)
773 {
774         struct proc_dir_entry* temp = root;
775
776         if (!temp)
777                 return 0;
778
779         if (!strcmp(temp->name, name))
780                 return temp;
781
782         if ((temp = lprocfs_bfs_srch(root->next, name)) != 0)
783                 return temp;
784
785         if ((temp = lprocfs_bfs_srch(root->subdir, name)) != 0)
786                 return temp;
787
788         return temp;
789 }
790
791 int lprocfs_get_nm(char* name, lprocfs_obd_nm_t* collection)
792 {
793         int i = 0;
794         while (collection[i].obd_names != 0) {
795                 if(!strcmp(collection[i].obd_clname, name))
796                         return i;
797                 i++;
798         }
799
800         return -1;
801 }
802
803 int lprocfs_dereg_dev(struct obd_device* device)
804 {
805         struct proc_dir_entry* temp;
806
807         CDEBUG(D_OTHER, "LPROCFS removing device = %s\n", device->obd_name);
808
809         if (!device) {
810                 CDEBUG(D_OTHER, "! LProcfs:  Null pointer !\n");
811                 return LPROCFS_SUCCESS;
812         }
813
814         if (!(device->obd_name)) {
815                 CERROR(" !! Device does not have a name !! \n");
816                 return LPROCFS_FAILURE;
817         }
818
819         temp = lprocfs_bfs_srch(proc_lustre_dev_root->subdir, device->obd_name);
820         if (temp == 0) {
821                 CERROR("Device %s not in lprocfs\n", device->obd_name);
822                 return LPROCFS_FAILURE;
823         }
824
825         lprocfs_remove_all(temp);
826
827         /*
828          * Free the memory held by counters
829          */
830         if (device->counters)
831                 OBD_FREE(device->counters, device->cntr_mem_size);
832
833         CDEBUG(D_OTHER, "LPROCFS removed device = %s\n", \
834                device->obd_name);
835
836         return LPROCFS_SUCCESS;
837 }
838
839 void lprocfs_remove_all(struct proc_dir_entry* root)
840 {
841         if (root->subdir != 0)
842                 lprocfs_remove_all(root->subdir);
843
844         if (root->next != 0)
845                 lprocfs_remove_all(root->next);
846
847         if (root->parent != 0)
848                 remove_proc_entry(root->name, root->parent);
849         else
850                 remove_proc_entry(root->name, NULL);
851 }
852
853 int rd_uuid(char* page, char **start, off_t off,
854             int count, int *eof, void *data)
855 {
856         int len;
857         struct obd_device *temp = (struct obd_device *)data;
858
859         len = sprintf(page, "%s\n", temp->obd_uuid);
860
861         return len;
862 }
863
864 int wr_uuid(struct file* file, const char *buffer,
865             unsigned long count, void *data)
866 {
867
868         return 0;
869 }
870
871 int rd_blksize(char* page, char **start, off_t off,
872                int count, int *eof, void *data)
873 {
874         //int len=0;
875         //struct obd_device *temp = (struct obd_device *)data;
876
877         return 0;
878
879 }
880 int rd_blktotal(char* page, char **start, off_t off,
881                 int count, int *eof, void *data)
882 {
883         return 0;
884 }
885
886 int rd_blkfree(char* page, char **start, off_t off,
887                int count, int *eof, void *data)
888 {
889         return 0;
890 }
891
892 int rd_kbfree(char* page, char **start, off_t off,
893               int count, int *eof, void *data)
894 {
895         return 0;
896 }
897
898 int rd_numobjects(char* page, char **start, off_t off,
899                   int count, int *eof, void *data)
900 {
901         return 0;
902 }
903
904 int rd_objfree(char* page, char **start, off_t off,
905                int count, int *eof, void *data)
906 {
907         return 0;
908 }
909
910 int rd_objgroups(char* page, char **start, off_t off,
911                  int count, int *eof, void *data)
912 {
913         return 0;
914 }
915
916
917 int lprocfs_ll_rd(char *page, char **start, off_t off,
918                   int count, int *eof, void *data)
919 {
920         __u64 *temp = (__u64 *)data;
921         int len;
922
923         len = snprintf(page, count, LPU64"\n", *temp);
924
925         return len;
926 }
927
928 int rd_fs_type(char* page, char **start, off_t off,
929                int count, int *eof, void *data)
930 {
931         return 0;
932 }
933
934 int rd_other(char* page, char **start, off_t off, int count, int *eof,
935              void *data)
936 {
937         return 0;
938 }
939
940 int rd_string(char* page, char **start, off_t off, int count, int *eof,
941               void *data)
942 {
943         printk("Hello string");
944         return 0;
945 }
946
947 int lprocfs_ll_wr(struct file* file, const char *buffer, unsigned long count,
948                   void *data)
949 {
950         return 0;
951 }
952
953 int wr_other(struct file* file, const char *buffer, unsigned long count,
954              void *data)
955 {
956         return 0;
957 }
958
959 int wr_string(struct file* file, const char *buffer, unsigned long count,
960               void *data)
961 {
962         return 0;
963 }
964
965 int lprocfs_reg_conn(unsigned int conn_number,
966                      struct lprocfs_conn_namespace* namespace)
967 {
968         return 0;
969 }
970
971 int lprocfs_dereg_conn(unsigned int conn_number)
972 {
973         return 0;
974 }
975
976 /*
977  * Import/Export APIs
978  */
979 int lprocfs_add_export(unsigned int conn_number, struct obd_device* device)
980 {
981         return 0;
982 }
983
984 int lprocfs_add_import(unsigned int conn_number, struct obd_device* device)
985 {
986         return 0;
987 }
988
989 int lprocfs_remove_export(unsigned int conn_number, struct obd_device* device)
990 {
991         return 0;
992 }
993
994 int lprocfs_remove_import(unsigned int conn_number, struct obd_device* device)
995 {
996         return 0;
997 }
998
999 #endif