Whamcloud - gitweb
b=15660
[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 = 0;
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 void lprocfs_free_client_stats(void *obj, void *data)
715 {
716         struct nid_stat *client_stat = obj;
717
718         CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
719                client_stat->nid_proc, client_stat->nid_stats,
720                client_stat->nid_brw_stats);
721
722         LASSERTF(client_stat->nid_exp_ref_count == 0, "count %d\n",
723                  client_stat->nid_exp_ref_count);
724
725         hlist_del_init(&client_stat->nid_hash);
726         list_del(&client_stat->nid_list);
727
728         if (client_stat->nid_proc)
729                 lprocfs_remove(&client_stat->nid_proc);
730
731         if (client_stat->nid_stats)
732                 lprocfs_free_stats(&client_stat->nid_stats);
733
734         if (client_stat->nid_brw_stats)
735                 OBD_FREE(client_stat->nid_brw_stats, sizeof(struct brw_stats));
736
737         OBD_FREE(client_stat, sizeof(*client_stat));
738         return;
739
740 }
741
742 void lprocfs_free_per_client_stats(struct obd_device *obd)
743 {
744         struct nid_stat *stat;
745         ENTRY;
746
747         /* we need extra list - because hash_exit called to early */
748         while(!list_empty(&obd->obd_nid_stats)) {
749                 stat = list_entry(obd->obd_nid_stats.next,
750                                   struct nid_stat, nid_list);
751                 lprocfs_free_client_stats(stat, NULL);
752         }
753
754         EXIT;
755 }
756
757 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
758                                           enum lprocfs_stats_flags flags)
759 {
760         struct lprocfs_stats *stats;
761         unsigned int percpusize;
762         unsigned int i, j;
763         unsigned int num_cpu;
764
765         if (num == 0)
766                 return NULL;
767
768         if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
769                 num_cpu = 1;
770         else
771                 num_cpu = num_possible_cpus();
772
773         OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
774         if (stats == NULL)
775                 return NULL;
776
777         if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
778                 stats->ls_flags = flags;
779                 spin_lock_init(&stats->ls_lock);
780                 /* Use this lock only if there are no percpu areas */
781         } else {
782                 stats->ls_flags = 0;
783         }
784
785         percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
786         if (num_cpu > 1)
787                 percpusize = L1_CACHE_ALIGN(percpusize);
788
789         for (i = 0; i < num_cpu; i++) {
790                 OBD_ALLOC(stats->ls_percpu[i], percpusize);
791                 if (stats->ls_percpu[i] == NULL) {
792                         for (j = 0; j < i; j++) {
793                                 OBD_FREE(stats->ls_percpu[j], percpusize);
794                                 stats->ls_percpu[j] = NULL;
795                         }
796                         break;
797                 }
798         }
799         if (stats->ls_percpu[0] == NULL) {
800                 OBD_FREE(stats, offsetof(typeof(*stats),
801                                          ls_percpu[num_cpu]));
802                 return NULL;
803         }
804
805         stats->ls_num = num;
806         return stats;
807 }
808
809 void lprocfs_free_stats(struct lprocfs_stats **statsh)
810 {
811         struct lprocfs_stats *stats = *statsh;
812         unsigned int num_cpu;
813         unsigned int percpusize;
814         unsigned int i;
815
816         if (stats == NULL || stats->ls_num == 0)
817                 return;
818         *statsh = NULL;
819
820         if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
821                 num_cpu = 1;
822         else
823                 num_cpu = num_possible_cpus();
824
825         percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
826         if (num_cpu > 1)
827                 percpusize = L1_CACHE_ALIGN(percpusize);
828         for (i = 0; i < num_cpu; i++)
829                 OBD_FREE(stats->ls_percpu[i], percpusize);
830         OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
831 }
832
833 void lprocfs_clear_stats(struct lprocfs_stats *stats)
834 {
835         struct lprocfs_counter *percpu_cntr;
836         int i,j;
837         unsigned int num_cpu;
838
839         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
840
841         for (i = 0; i < num_cpu; i++) {
842                 for (j = 0; j < stats->ls_num; j++) {
843                         percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
844                         atomic_inc(&percpu_cntr->lc_cntl.la_entry);
845                         percpu_cntr->lc_count = 0;
846                         percpu_cntr->lc_sum = 0;
847                         percpu_cntr->lc_min = LC_MIN_INIT;
848                         percpu_cntr->lc_max = 0;
849                         percpu_cntr->lc_sumsquare = 0;
850                         atomic_inc(&percpu_cntr->lc_cntl.la_exit);
851                 }
852         }
853
854         lprocfs_stats_unlock(stats);
855 }
856
857 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
858                                        size_t len, loff_t *off)
859 {
860         struct seq_file *seq = file->private_data;
861         struct lprocfs_stats *stats = seq->private;
862
863         lprocfs_clear_stats(stats);
864
865         return len;
866 }
867
868 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
869 {
870         struct lprocfs_stats *stats = p->private;
871         /* return 1st cpu location */
872         return (*pos >= stats->ls_num) ? NULL :
873                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
874 }
875
876 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
877 {
878 }
879
880 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
881 {
882         struct lprocfs_stats *stats = p->private;
883         ++*pos;
884         return (*pos >= stats->ls_num) ? NULL :
885                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
886 }
887
888 /* seq file export of one lprocfs counter */
889 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
890 {
891        struct lprocfs_stats *stats = p->private;
892        struct lprocfs_counter  *cntr = v;
893        struct lprocfs_counter  t, ret = { .lc_min = LC_MIN_INIT };
894        int i, idx, rc;
895        unsigned int num_cpu;
896
897        if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
898                struct timeval now;
899                do_gettimeofday(&now);
900                rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
901                                "snapshot_time", now.tv_sec, now.tv_usec);
902                if (rc < 0)
903                        return rc;
904        }
905        idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
906
907        if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
908                num_cpu = 1;
909        else
910                num_cpu = num_possible_cpus();
911
912        for (i = 0; i < num_cpu; i++) {
913                struct lprocfs_counter *percpu_cntr =
914                        &(stats->ls_percpu[i])->lp_cntr[idx];
915                int centry;
916
917                do {
918                        centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
919                        t.lc_count = percpu_cntr->lc_count;
920                        t.lc_sum = percpu_cntr->lc_sum;
921                        t.lc_min = percpu_cntr->lc_min;
922                        t.lc_max = percpu_cntr->lc_max;
923                        t.lc_sumsquare = percpu_cntr->lc_sumsquare;
924                } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
925                         centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
926                ret.lc_count += t.lc_count;
927                ret.lc_sum += t.lc_sum;
928                if (t.lc_min < ret.lc_min)
929                        ret.lc_min = t.lc_min;
930                if (t.lc_max > ret.lc_max)
931                        ret.lc_max = t.lc_max;
932                ret.lc_sumsquare += t.lc_sumsquare;
933        }
934
935        rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
936                        ret.lc_count, cntr->lc_units);
937        if (rc < 0)
938                goto out;
939
940        if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
941                rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
942                                ret.lc_min, ret.lc_max, ret.lc_sum);
943                if (rc < 0)
944                        goto out;
945                if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
946                        rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
947                if (rc < 0)
948                        goto out;
949        }
950        rc = seq_printf(p, "\n");
951  out:
952        return (rc < 0) ? rc : 0;
953 }
954
955 struct seq_operations lprocfs_stats_seq_sops = {
956         start: lprocfs_stats_seq_start,
957         stop:  lprocfs_stats_seq_stop,
958         next:  lprocfs_stats_seq_next,
959         show:  lprocfs_stats_seq_show,
960 };
961
962 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
963 {
964         struct proc_dir_entry *dp = PDE(inode);
965         struct seq_file *seq;
966         int rc;
967
968         LPROCFS_ENTRY_AND_CHECK(dp);
969         rc = seq_open(file, &lprocfs_stats_seq_sops);
970         if (rc) {
971                 LPROCFS_EXIT();
972                 return rc;
973         }
974         seq = file->private_data;
975         seq->private = dp->data;
976         return 0;
977 }
978
979 struct file_operations lprocfs_stats_seq_fops = {
980         .owner   = THIS_MODULE,
981         .open    = lprocfs_stats_seq_open,
982         .read    = seq_read,
983         .write   = lprocfs_stats_seq_write,
984         .llseek  = seq_lseek,
985         .release = lprocfs_seq_release,
986 };
987
988 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
989                            struct lprocfs_stats *stats)
990 {
991         struct proc_dir_entry *entry;
992         LASSERT(root != NULL);
993
994         entry = create_proc_entry(name, 0644, root);
995         if (entry == NULL)
996                 return -ENOMEM;
997         entry->proc_fops = &lprocfs_stats_seq_fops;
998         entry->data = (void *)stats;
999         return 0;
1000 }
1001
1002 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1003                           unsigned conf, const char *name, const char *units)
1004 {
1005         struct lprocfs_counter *c;
1006         int i;
1007         unsigned int num_cpu;
1008
1009         LASSERT(stats != NULL);
1010
1011         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1012
1013         for (i = 0; i < num_cpu; i++) {
1014                 c = &(stats->ls_percpu[i]->lp_cntr[index]);
1015                 c->lc_config = conf;
1016                 c->lc_count = 0;
1017                 c->lc_sum = 0;
1018                 c->lc_min = LC_MIN_INIT;
1019                 c->lc_max = 0;
1020                 c->lc_name = name;
1021                 c->lc_units = units;
1022         }
1023
1024         lprocfs_stats_unlock(stats);
1025 }
1026 EXPORT_SYMBOL(lprocfs_counter_init);
1027
1028 #define LPROCFS_OBD_OP_INIT(base, stats, op)                               \
1029 do {                                                                       \
1030         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);              \
1031         LASSERT(coffset < stats->ls_num);                                  \
1032         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");              \
1033 } while (0)
1034
1035 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1036 {
1037         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1038         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1039         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1040         LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1041         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1042         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1043         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1044         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1045         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1046         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1047         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1048         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1049         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1050         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1051         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1052         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1053         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1054         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1055         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1056         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1057         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1058         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1059         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1060         LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
1061         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1062         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1063         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1064         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1065         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1066         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1067         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1068         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1069         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1070         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
1071         LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
1072         LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
1073         LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
1074         LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
1075         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
1076         LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
1077         LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1078         LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1079         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1080         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1081         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1082         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1083         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1084         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1085         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1086         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1087         LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
1088         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1089         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1090         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1091         LPROCFS_OBD_OP_INIT(num_private_stats, stats, join_lru);
1092         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1093         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1094         LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1095         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1096         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1097         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1098         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1099         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1100         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1101         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1102         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1103         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1104         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1105         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1106 }
1107
1108 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1109 {
1110         struct lprocfs_stats *stats;
1111         unsigned int num_stats;
1112         int rc, i;
1113
1114         LASSERT(obd->obd_stats == NULL);
1115         LASSERT(obd->obd_proc_entry != NULL);
1116         LASSERT(obd->obd_cntr_base == 0);
1117
1118         num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1119                 num_private_stats - 1 /* o_owner */;
1120         stats = lprocfs_alloc_stats(num_stats, 0);
1121         if (stats == NULL)
1122                 return -ENOMEM;
1123
1124         lprocfs_init_ops_stats(num_private_stats, stats);
1125
1126         for (i = num_private_stats; i < num_stats; i++) {
1127                 /* If this LBUGs, it is likely that an obd
1128                  * operation was added to struct obd_ops in
1129                  * <obd.h>, and that the corresponding line item
1130                  * LPROCFS_OBD_OP_INIT(.., .., opname)
1131                  * is missing from the list above. */
1132                 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1133                          "Missing obd_stat initializer obd_op "
1134                          "operation at offset %d.\n", i - num_private_stats);
1135         }
1136         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1137         if (rc < 0) {
1138                 lprocfs_free_stats(&stats);
1139         } else {
1140                 obd->obd_stats  = stats;
1141                 obd->obd_cntr_base = num_private_stats;
1142         }
1143         return rc;
1144 }
1145
1146 void lprocfs_free_obd_stats(struct obd_device *obd)
1147 {
1148         if (obd->obd_stats) 
1149                 lprocfs_free_stats(&obd->obd_stats);
1150 }
1151
1152 #define LPROCFS_MD_OP_INIT(base, stats, op)                             \
1153 do {                                                                    \
1154         unsigned int coffset = base + MD_COUNTER_OFFSET(op);            \
1155         LASSERT(coffset < stats->ls_num);                               \
1156         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
1157 } while (0)
1158
1159 int lprocfs_alloc_md_stats(struct obd_device *obd,
1160                            unsigned num_private_stats)
1161 {
1162         struct lprocfs_stats *stats;
1163         unsigned int num_stats;
1164         int rc, i;
1165
1166         LASSERT(obd->md_stats == NULL);
1167         LASSERT(obd->obd_proc_entry != NULL);
1168         LASSERT(obd->md_cntr_base == 0);
1169
1170         num_stats = 1 + MD_COUNTER_OFFSET(get_remote_perm) +
1171                     num_private_stats;
1172         stats = lprocfs_alloc_stats(num_stats, 0);
1173         if (stats == NULL)
1174                 return -ENOMEM;
1175
1176         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1177         LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1178         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1179         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1180         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1181         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1182         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1183         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1184         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1185         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1186         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1187         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1188         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1189         LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1190         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1191         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1192         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1193         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1194         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1195         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1196         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1197         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1198         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1199         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1200         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1201         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1202         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1203         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1204
1205         for (i = num_private_stats; i < num_stats; i++) {
1206                 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1207                         CERROR("Missing md_stat initializer md_op "
1208                                "operation at offset %d. Aborting.\n",
1209                                i - num_private_stats);
1210                         LBUG();
1211                 }
1212         }
1213         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1214         if (rc < 0) {
1215                 lprocfs_free_stats(&stats);
1216         } else {
1217                 obd->md_stats  = stats;
1218                 obd->md_cntr_base = num_private_stats;
1219         }
1220         return rc;
1221 }
1222
1223 void lprocfs_free_md_stats(struct obd_device *obd)
1224 {
1225         struct lprocfs_stats *stats = obd->md_stats;
1226
1227         if (stats != NULL) {
1228                 obd->md_stats = NULL;
1229                 lprocfs_free_stats(&stats);
1230         }
1231 }
1232
1233 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1234                          int *eof,  void *data)
1235 {
1236         struct obd_export *exp = (struct obd_export*)data;
1237         LASSERT(exp != NULL);
1238         *eof = 1;
1239         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1240 }
1241
1242 struct exp_uuid_cb_data {
1243         char                   *page;
1244         int                     count;
1245         int                    *eof;
1246         int                    *len;
1247 };
1248
1249 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1250 {
1251         struct obd_export *exp = (struct obd_export *)obj;
1252         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1253
1254         if (exp->exp_nid_stats)
1255                 *data->len += snprintf((data->page + *data->len),
1256                                        data->count, "%s\n",
1257                                        obd_uuid2str(&exp->exp_client_uuid));
1258 }
1259
1260 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1261                         int *eof,  void *data)
1262 {
1263         struct nid_stat *stats = (struct nid_stat *)data;
1264         struct exp_uuid_cb_data cb_data;
1265         struct obd_device *obd = stats->nid_obd;
1266         int len = 0;
1267
1268         *eof = 1;
1269         page[0] = '\0';
1270         LASSERT(obd != NULL);
1271
1272         cb_data.page = page;
1273         cb_data.count = count;
1274         cb_data.eof = eof;
1275         cb_data.len = &len;
1276         lustre_hash_bucket_iterate(obd->obd_nid_hash_body,
1277                                    &stats->nid, lprocfs_exp_print_uuid,
1278                                    &cb_data);
1279         return (*cb_data.len);
1280 }
1281
1282 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1283                                         int count, int *eof,  void *data)
1284 {
1285         *eof = 1;
1286         return snprintf(page, count, "%s\n",
1287                         "Write into this file to clear all nid stats and "
1288                         "stale nid entries");
1289 }
1290 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1291
1292 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1293 {
1294         struct nid_stat *client_stat = obj;
1295         int i;
1296         if(client_stat->nid_exp_ref_count == 1) {
1297                 hlist_del_init(&client_stat->nid_hash);
1298                 lprocfs_free_client_stats(client_stat, data);
1299                 OBD_FREE(client_stat, sizeof(struct nid_stat));
1300                 EXIT;
1301                 return;
1302         }
1303
1304         /* we has reference to object - only clear data*/
1305         if (client_stat->nid_stats) {
1306                 lprocfs_clear_stats(client_stat->nid_stats);
1307         }
1308         if (client_stat->nid_brw_stats) {
1309                 for (i = 0; i < BRW_LAST; i++)
1310                         lprocfs_oh_clear(&client_stat->nid_brw_stats->hist[i]);
1311         }
1312         EXIT;
1313         return;
1314 }
1315
1316 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1317                                          unsigned long count, void *data)
1318 {
1319         struct obd_device *obd = (struct obd_device *)data;
1320         lustre_hash_iterate_all(obd->obd_nid_stats_hash_body,
1321                                 lprocfs_free_client_stats, NULL);
1322         return count;
1323 }
1324 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1325
1326 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1327 {
1328         int rc = 0;
1329         struct nid_stat *tmp = NULL, *tmp1;
1330         struct obd_device *obd = NULL;
1331         ENTRY;
1332
1333         *newnid = 0;
1334
1335         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1336             !exp->exp_obd->obd_nid_stats_hash_body)
1337                 RETURN(-EINVAL);
1338
1339         /* not test against zero because eric say:
1340          * You may only test nid against another nid, or LNET_NID_ANY.  Anything else is
1341          * nonsense.*/
1342         if (!nid || *nid == LNET_NID_ANY)
1343                 RETURN(0);
1344
1345         obd = exp->exp_obd;
1346
1347         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash_body);
1348
1349         OBD_ALLOC(tmp, sizeof(struct nid_stat));
1350         if (tmp == NULL)
1351                 RETURN(-ENOMEM);
1352
1353         tmp->nid = *nid;
1354         tmp->nid_obd = exp->exp_obd;
1355         tmp->nid_exp_ref_count = 1; /* need live in hash after destroy export */
1356
1357         tmp1= lustre_hash_findadd_unique(obd->obd_nid_stats_hash_body, nid,
1358                                          &tmp->nid_hash);
1359         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1360                tmp1, libcfs_nid2str(*nid), tmp->nid_exp_ref_count);
1361
1362         if (tmp1 != tmp) {
1363                 exp->exp_nid_stats = tmp1;
1364                 GOTO(destroy_new, rc = 0);
1365         }
1366         /* not found - create */
1367         tmp->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1368                                          obd->obd_proc_exports_entry, NULL, NULL);
1369         if (!tmp->nid_proc) {
1370                 CERROR("Error making export directory for"
1371                        " nid %s\n", libcfs_nid2str(*nid));
1372                 lustre_hash_delitem(obd->obd_nid_stats_hash_body, nid,
1373                                     &tmp->nid_hash);
1374                 GOTO(destroy_new, rc = -ENOMEM);
1375         }
1376
1377         rc = lprocfs_add_simple(tmp->nid_proc, "uuid",
1378                                 lprocfs_exp_rd_uuid, NULL, tmp);
1379         if (rc)
1380                 CWARN("Error adding the uuid file\n");
1381
1382         spin_lock(&obd->obd_nid_lock);
1383         list_add(&tmp->nid_list, &obd->obd_nid_stats);
1384         spin_unlock(&obd->obd_nid_lock);
1385
1386         exp->exp_nid_stats = tmp;
1387         *newnid = 1;
1388         RETURN(rc);
1389
1390 destroy_new:
1391         OBD_FREE(tmp, sizeof(struct nid_stat));
1392         RETURN(rc);
1393 }
1394
1395 int lprocfs_exp_cleanup(struct obd_export *exp)
1396 {
1397         struct nid_stat *stat = exp->exp_nid_stats;
1398
1399         if(!stat)
1400                 RETURN(0);
1401
1402         stat->nid_exp_ref_count--;
1403         CDEBUG(D_INFO, "Put stat %p - %d\n", stat, stat->nid_exp_ref_count);
1404
1405         exp->exp_nid_stats = NULL;
1406         return 0;
1407 }
1408
1409 int lprocfs_write_helper(const char *buffer, unsigned long count,
1410                          int *val)
1411 {
1412         return lprocfs_write_frac_helper(buffer, count, val, 1);
1413 }
1414
1415 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1416                               int *val, int mult)
1417 {
1418         char kernbuf[20], *end, *pbuf;
1419
1420         if (count > (sizeof(kernbuf) - 1))
1421                 return -EINVAL;
1422
1423         if (copy_from_user(kernbuf, buffer, count))
1424                 return -EFAULT;
1425
1426         kernbuf[count] = '\0';
1427         pbuf = kernbuf;
1428         if (*pbuf == '-') {
1429                 mult = -mult;
1430                 pbuf++;
1431         }
1432
1433         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1434         if (pbuf == end)
1435                 return -EINVAL;
1436
1437         if (end != NULL && *end == '.') {
1438                 int temp_val, pow = 1;
1439                 int i;
1440
1441                 pbuf = end + 1;
1442                 if (strlen(pbuf) > 5)
1443                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
1444
1445                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1446
1447                 if (pbuf < end) {
1448                         for (i = 0; i < (end - pbuf); i++)
1449                                 pow *= 10;
1450
1451                         *val += temp_val / pow;
1452                 }
1453         }
1454         return 0;
1455 }
1456
1457 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1458 {
1459         long decimal_val, frac_val;
1460         int prtn;
1461
1462         if (count < 10)
1463                 return -EINVAL;
1464
1465         decimal_val = val / mult;
1466         prtn = snprintf(buffer, count, "%ld", decimal_val);
1467         frac_val = val % mult;
1468
1469         if (prtn < (count - 4) && frac_val > 0) {
1470                 long temp_frac;
1471                 int i, temp_mult = 1, frac_bits = 0;
1472
1473                 temp_frac = frac_val * 10;
1474                 buffer[prtn++] = '.';
1475                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) { /*only reserved 2bits fraction*/
1476                         buffer[prtn++] ='0';
1477                         temp_frac *= 10;
1478                         frac_bits++;
1479                 }
1480                 /*
1481                   Need to think these cases :
1482                         1. #echo x.00 > /proc/xxx       output result : x
1483                         2. #echo x.0x > /proc/xxx       output result : x.0x
1484                         3. #echo x.x0 > /proc/xxx       output result : x.x
1485                         4. #echo x.xx > /proc/xxx       output result : x.xx
1486                         Only reserved 2bits fraction.       
1487                  */
1488                 for (i = 0; i < (5 - prtn); i++)
1489                         temp_mult *= 10;
1490
1491                 frac_bits = min((int)count - prtn, 3 - frac_bits);
1492                 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1493
1494                 prtn--;
1495                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1496                         prtn--;
1497                         if (buffer[prtn] == '.') {
1498                                 prtn--;
1499                                 break;
1500                         }
1501                 }
1502                 prtn++;
1503         }
1504         buffer[prtn++] ='\n';
1505         return prtn;
1506 }
1507
1508 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1509 {
1510         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1511 }
1512
1513 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1514                               __u64 *val, int mult)
1515 {
1516         char kernbuf[22], *end, *pbuf;
1517         __u64 whole, frac = 0, units;
1518         unsigned frac_d = 1;
1519
1520         if (count > (sizeof(kernbuf) - 1) )
1521                 return -EINVAL;
1522
1523         if (copy_from_user(kernbuf, buffer, count))
1524                 return -EFAULT;
1525
1526         kernbuf[count] = '\0';
1527         pbuf = kernbuf;
1528         if (*pbuf == '-') {
1529                 mult = -mult;
1530                 pbuf++;
1531         }
1532
1533         whole = simple_strtoull(pbuf, &end, 10);
1534         if (pbuf == end)
1535                 return -EINVAL;
1536
1537         if (end != NULL && *end == '.') {
1538                 int i;
1539                 pbuf = end + 1;
1540
1541                 /* need to limit frac_d to a __u32 */
1542                 if (strlen(pbuf) > 10)
1543                         pbuf[10] = '\0';
1544
1545                 frac = simple_strtoull(pbuf, &end, 10);
1546                 /* count decimal places */
1547                 for (i = 0; i < (end - pbuf); i++)
1548                         frac_d *= 10;
1549         }
1550
1551         units = 1;
1552         switch(*end) {
1553         case 'p': case 'P':
1554                 units <<= 10;
1555         case 't': case 'T':
1556                 units <<= 10;
1557         case 'g': case 'G':
1558                 units <<= 10;
1559         case 'm': case 'M':
1560                 units <<= 10;
1561         case 'k': case 'K':
1562                 units <<= 10;
1563         }
1564         /* Specified units override the multiplier */
1565         if (units) 
1566                 mult = mult < 0 ? -units : units;
1567
1568         frac *= mult;
1569         do_div(frac, frac_d);
1570         *val = whole * mult + frac;
1571         return 0;
1572 }
1573
1574 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, 
1575                        char *name, mode_t mode,
1576                        struct file_operations *seq_fops, void *data)
1577 {
1578         struct proc_dir_entry *entry;
1579         ENTRY;
1580
1581         entry = create_proc_entry(name, mode, parent);
1582         if (entry == NULL)
1583                 RETURN(-ENOMEM);
1584         entry->proc_fops = seq_fops;
1585         entry->data = data;
1586
1587         RETURN(0);
1588 }
1589 EXPORT_SYMBOL(lprocfs_seq_create);
1590
1591 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1592                                       mode_t mode,
1593                                       struct file_operations *seq_fops,
1594                                       void *data)
1595 {
1596         return (lprocfs_seq_create(dev->obd_proc_entry, name, 
1597                                    mode, seq_fops, data));
1598 }
1599 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1600
1601 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1602 {
1603         if (value >= OBD_HIST_MAX)
1604                 value = OBD_HIST_MAX - 1;
1605
1606         spin_lock(&oh->oh_lock);
1607         oh->oh_buckets[value]++;
1608         spin_unlock(&oh->oh_lock);
1609 }
1610 EXPORT_SYMBOL(lprocfs_oh_tally);
1611
1612 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1613 {
1614         unsigned int val;
1615
1616         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1617                 ;
1618
1619         lprocfs_oh_tally(oh, val);
1620 }
1621 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1622
1623 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1624 {
1625         unsigned long ret = 0;
1626         int i;
1627
1628         for (i = 0; i < OBD_HIST_MAX; i++)
1629                 ret +=  oh->oh_buckets[i];
1630         return ret;
1631 }
1632 EXPORT_SYMBOL(lprocfs_oh_sum);
1633
1634 void lprocfs_oh_clear(struct obd_histogram *oh)
1635 {
1636         spin_lock(&oh->oh_lock);
1637         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1638         spin_unlock(&oh->oh_lock);
1639 }
1640 EXPORT_SYMBOL(lprocfs_oh_clear);
1641
1642 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1643                                    int count, int *eof, void *data)
1644 {
1645         struct obd_device *obd = data;
1646         int len = 0, size;
1647
1648         LASSERT(obd != NULL);
1649         LASSERT(count >= 0);
1650
1651         /* Set start of user data returned to
1652            page + off since the user may have
1653            requested to read much smaller than
1654            what we need to read */
1655         *start = page + off;
1656
1657         /* We know we are allocated a page here.
1658            Also we know that this function will
1659            not need to write more than a page
1660            so we can truncate at CFS_PAGE_SIZE.  */
1661         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
1662
1663         /* Initialize the page */
1664         memset(page, 0, size);
1665
1666         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
1667                 goto out;
1668
1669         if (obd->obd_max_recoverable_clients == 0) {
1670                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
1671                         goto out;
1672
1673                 goto fclose;
1674         }
1675
1676         /* sampled unlocked, but really... */
1677         if (obd->obd_recovering == 0) {
1678                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
1679                         goto out;
1680
1681                 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1682                     obd->obd_recovery_start) <= 0)
1683                         goto out;
1684
1685                 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_end: %lu\n",
1686                     obd->obd_recovery_end) <= 0)
1687                         goto out;
1688
1689                 /* Number of clients have have completed recovery */
1690                 if (lprocfs_obd_snprintf(&page, size, &len, "recovered_clients: %d\n",
1691                     obd->obd_max_recoverable_clients - obd->obd_recoverable_clients) <= 0)
1692                         goto out;
1693
1694                 if (lprocfs_obd_snprintf(&page, size, &len, "unrecovered_clients: %d\n",
1695                     obd->obd_recoverable_clients) <= 0)
1696                         goto out;
1697
1698                 if (lprocfs_obd_snprintf(&page, size, &len, "last_transno: "LPD64"\n",
1699                     obd->obd_next_recovery_transno - 1) <= 0)
1700                         goto out;
1701
1702                 lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d\n", obd->obd_replayed_requests);
1703                 goto fclose;
1704         }
1705
1706         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
1707                 goto out;
1708
1709         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1710             obd->obd_recovery_start) <= 0)
1711                 goto out;
1712
1713         if (lprocfs_obd_snprintf(&page, size, &len, "time remaining: %lu\n",
1714                                  cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
1715                                  obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
1716                 goto out;
1717
1718         if(lprocfs_obd_snprintf(&page, size, &len, "connected_clients: %d/%d\n",
1719                                 obd->obd_connected_clients,
1720                                 obd->obd_max_recoverable_clients) <= 0)
1721                 goto out;
1722
1723         /* Number of clients have have completed recovery */
1724         if (lprocfs_obd_snprintf(&page, size, &len, "completed_clients: %d/%d\n",
1725                                  obd->obd_max_recoverable_clients - obd->obd_recoverable_clients,
1726                                  obd->obd_max_recoverable_clients) <= 0)
1727                 goto out;
1728
1729         if (lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d/??\n",
1730                                  obd->obd_replayed_requests) <= 0)
1731                 goto out;
1732
1733         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1734                                  obd->obd_requests_queued_for_recovery) <= 0)
1735                 goto out;
1736
1737         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n", 
1738                                  obd->obd_next_recovery_transno) <= 0)
1739                 goto out;
1740
1741 fclose:
1742         *eof = 1;
1743 out:
1744         return min(count, len - (int)off);
1745 }
1746 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1747
1748 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
1749                                     int count, int *eof, void *data)
1750 {
1751         struct obd_device *obd = (struct obd_device *)data;
1752         LASSERT(obd != NULL);
1753
1754         return snprintf(page, count, "%lu\n", 
1755                         obd->obd_recovery_max_time);
1756 }
1757 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
1758
1759 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
1760                                     unsigned long count, void *data)
1761 {
1762         struct obd_device *obd = (struct obd_device *)data;
1763         int val, rc;
1764         LASSERT(obd != NULL);
1765
1766         rc = lprocfs_write_helper(buffer, count, &val);
1767         if (rc)
1768                 return rc;
1769
1770         obd->obd_recovery_max_time = val;
1771         return count;
1772 }
1773 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
1774
1775 EXPORT_SYMBOL(lprocfs_register);
1776 EXPORT_SYMBOL(lprocfs_srch);
1777 EXPORT_SYMBOL(lprocfs_remove);
1778 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
1779 EXPORT_SYMBOL(lprocfs_add_vars);
1780 EXPORT_SYMBOL(lprocfs_obd_setup);
1781 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1782 EXPORT_SYMBOL(lprocfs_add_simple);
1783 EXPORT_SYMBOL(lprocfs_add_symlink);
1784 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
1785 EXPORT_SYMBOL(lprocfs_alloc_stats);
1786 EXPORT_SYMBOL(lprocfs_free_stats);
1787 EXPORT_SYMBOL(lprocfs_clear_stats);
1788 EXPORT_SYMBOL(lprocfs_register_stats);
1789 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1790 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1791 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1792 EXPORT_SYMBOL(lprocfs_exp_setup);
1793 EXPORT_SYMBOL(lprocfs_exp_cleanup);
1794
1795 EXPORT_SYMBOL(lprocfs_rd_u64);
1796 EXPORT_SYMBOL(lprocfs_rd_atomic);
1797 EXPORT_SYMBOL(lprocfs_wr_atomic);
1798 EXPORT_SYMBOL(lprocfs_rd_uint);
1799 EXPORT_SYMBOL(lprocfs_wr_uint);
1800 EXPORT_SYMBOL(lprocfs_rd_uuid);
1801 EXPORT_SYMBOL(lprocfs_rd_name);
1802 EXPORT_SYMBOL(lprocfs_rd_fstype);
1803 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
1804 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
1805 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1806 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1807
1808 EXPORT_SYMBOL(lprocfs_rd_blksize);
1809 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
1810 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
1811 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
1812 EXPORT_SYMBOL(lprocfs_rd_filestotal);
1813 EXPORT_SYMBOL(lprocfs_rd_filesfree);
1814
1815 EXPORT_SYMBOL(lprocfs_write_helper);
1816 EXPORT_SYMBOL(lprocfs_write_frac_helper);
1817 EXPORT_SYMBOL(lprocfs_read_frac_helper);
1818 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1819 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
1820 #endif /* LPROCFS*/