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