Whamcloud - gitweb
Obsolete CURRENT_SECONDS and use cfs_time_current_sec() instead.
[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 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
120                                  size_t size, loff_t *ppos)
121 {
122         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
123         char *page, *start = NULL;
124         int rc = 0, eof = 1, count;
125
126         if (*ppos >= CFS_PAGE_SIZE)
127                 return 0;
128
129         page = (char *)__get_free_page(GFP_KERNEL);
130         if (page == NULL)
131                 return -ENOMEM;
132
133         LPROCFS_ENTRY();
134         OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
135         if (!dp->deleted && dp->read_proc)
136                 rc = dp->read_proc(page, &start, *ppos, CFS_PAGE_SIZE, 
137                         &eof, dp->data);
138         LPROCFS_EXIT();
139         if (rc <= 0)
140                 goto out;
141
142         /* for lustre proc read, the read count must be less than PAGE_SIZE */
143         LASSERT(eof == 1);
144
145         if (start == NULL) {
146                 rc -= *ppos;
147                 if (rc < 0)
148                         rc = 0;
149                 if (rc == 0)
150                         goto out;
151                 start = page + *ppos;
152         } else if (start < page) {
153                 start = page;
154         }
155
156         count = (rc < size) ? rc : size;
157         if (copy_to_user(buf, start, count)) {
158                 rc = -EFAULT;
159                 goto out;
160         }
161         *ppos += count;
162
163 out:
164         free_page((unsigned long)page);
165         return rc;
166 }
167
168 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf, size_t size, loff_t *ppos)
169 {
170         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
171         int rc = 0;
172
173         LPROCFS_ENTRY();
174         if (!dp->deleted && dp->write_proc)
175                 rc = dp->write_proc(f, buf, size, dp->data);
176         LPROCFS_EXIT();
177         return rc;
178 }
179
180 static struct file_operations lprocfs_generic_fops = {
181         .owner = THIS_MODULE,
182         .read = lprocfs_fops_read,
183         .write = lprocfs_fops_write,
184 };
185
186 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
187 {
188         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
189         struct obd_device *obd = dp->data;
190
191         atomic_inc(&obd->obd_evict_inprogress);
192
193         return 0;
194 }
195
196 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
197 {
198         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
199         struct obd_device *obd = dp->data;
200
201         atomic_dec(&obd->obd_evict_inprogress);
202         wake_up(&obd->obd_evict_inprogress_waitq);
203
204         return 0;
205 }
206
207 struct file_operations lprocfs_evict_client_fops = {
208         .owner = THIS_MODULE,
209         .read = lprocfs_fops_read,
210         .write = lprocfs_fops_write,
211         .open = lprocfs_evict_client_open,
212         .release = lprocfs_evict_client_release,
213 };
214 EXPORT_SYMBOL(lprocfs_evict_client_fops);
215
216 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
217                      void *data)
218 {
219         if (root == NULL || list == NULL)
220                 return -EINVAL;
221
222         while (list->name != NULL) {
223                 struct proc_dir_entry *cur_root, *proc;
224                 char *pathcopy, *cur, *next, pathbuf[64];
225                 int pathsize = strlen(list->name) + 1;
226
227                 proc = NULL;
228                 cur_root = root;
229
230                 /* need copy of path for strsep */
231                 if (strlen(list->name) > sizeof(pathbuf) - 1) {
232                         OBD_ALLOC(pathcopy, pathsize);
233                         if (pathcopy == NULL)
234                                 return -ENOMEM;
235                 } else {
236                         pathcopy = pathbuf;
237                 }
238
239                 next = pathcopy;
240                 strcpy(pathcopy, list->name);
241
242                 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
243                         if (*cur =='\0') /* skip double/trailing "/" */
244                                 continue;
245
246                         proc = lprocfs_srch(cur_root, cur);
247                         CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
248                                cur_root->name, cur, next,
249                                (proc ? "exists" : "new"));
250                         if (next != NULL) {
251                                 cur_root = (proc ? proc :
252                                             proc_mkdir(cur, cur_root));
253                         } else if (proc == NULL) {
254                                 mode_t mode = 0;
255                                 if (list->read_fptr)
256                                         mode = 0444;
257                                 if (list->write_fptr)
258                                         mode |= 0200;
259                                 proc = create_proc_entry(cur, mode, cur_root);
260                         }
261                 }
262
263                 if (pathcopy != pathbuf)
264                         OBD_FREE(pathcopy, pathsize);
265
266                 if (cur_root == NULL || proc == NULL) {
267                         CERROR("LprocFS: No memory to create /proc entry %s",
268                                list->name);
269                         return -ENOMEM;
270                 }
271
272                 if (list->fops)
273                         proc->proc_fops = list->fops;
274                 else
275                         proc->proc_fops = &lprocfs_generic_fops;
276                 proc->read_proc = list->read_fptr;
277                 proc->write_proc = list->write_fptr;
278                 proc->data = (list->data ? list->data : data);
279                 list++;
280         }
281         return 0;
282 }
283
284 void lprocfs_remove(struct proc_dir_entry **rooth)
285 {
286         struct proc_dir_entry *root = *rooth;
287         struct proc_dir_entry *temp = root;
288         struct proc_dir_entry *rm_entry;
289         struct proc_dir_entry *parent;
290
291         if (!root)
292                 return;
293         *rooth = NULL;
294
295         parent = root->parent;
296         LASSERT(parent != NULL);
297
298         while (1) {
299                 while (temp->subdir != NULL)
300                         temp = temp->subdir;
301
302                 rm_entry = temp;
303                 temp = temp->parent;
304
305                 /* Memory corruption once caused this to fail, and
306                    without this LASSERT we would loop here forever. */
307                 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
308                          "0x%p  %s/%s len %d\n", rm_entry, temp->name,
309                          rm_entry->name, (int)strlen(rm_entry->name));
310
311                 /* Now, the rm_entry->deleted flags is protected 
312                  * by _lprocfs_lock. */
313                 down_write(&_lprocfs_lock);
314                 rm_entry->data = NULL;
315                 remove_proc_entry(rm_entry->name, temp);
316                 up_write(&_lprocfs_lock);
317                 if (temp == parent)
318                         break;
319         }
320 }
321
322 struct proc_dir_entry *lprocfs_register(const char *name,
323                                         struct proc_dir_entry *parent,
324                                         struct lprocfs_vars *list, void *data)
325 {
326         struct proc_dir_entry *newchild;
327
328         newchild = lprocfs_srch(parent, name);
329         if (newchild != NULL) {
330                 CERROR(" Lproc: Attempting to register %s more than once \n",
331                        name);
332                 return ERR_PTR(-EALREADY);
333         }
334
335         newchild = proc_mkdir(name, parent);
336         if (newchild != NULL && list != NULL) {
337                 int rc = lprocfs_add_vars(newchild, list, data);
338                 if (rc) {
339                         lprocfs_remove(&newchild);
340                         return ERR_PTR(rc);
341                 }
342         }
343         return newchild;
344 }
345
346 /* Generic callbacks */
347 int lprocfs_rd_uint(char *page, char **start, off_t off,
348                     int count, int *eof, void *data)
349 {
350         unsigned int *temp = (unsigned int *)data;
351         return snprintf(page, count, "%u\n", *temp);
352 }
353
354 int lprocfs_wr_uint(struct file *file, const char *buffer,
355                     unsigned long count, void *data)
356 {
357         unsigned *p = data;
358         char dummy[MAX_STRING_SIZE + 1], *end;
359         unsigned long tmp;
360
361         dummy[MAX_STRING_SIZE] = '\0';
362         if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))
363                 return -EFAULT;
364
365         tmp = simple_strtoul(dummy, &end, 0);
366         if (dummy == end)
367                 return -EINVAL;
368
369         *p = (unsigned int)tmp;
370         return count;
371 }
372
373 int lprocfs_rd_u64(char *page, char **start, off_t off,
374                    int count, int *eof, void *data)
375 {
376         LASSERT(data != NULL);
377         *eof = 1;
378         return snprintf(page, count, LPU64"\n", *(__u64 *)data);
379 }
380
381 int lprocfs_rd_atomic(char *page, char **start, off_t off,
382                    int count, int *eof, void *data)
383 {
384         atomic_t *atom = (atomic_t *)data;
385         LASSERT(atom != NULL);
386         *eof = 1;
387         return snprintf(page, count, "%d\n", atomic_read(atom));
388 }
389
390 int lprocfs_wr_atomic(struct file *file, const char *buffer,
391                       unsigned long count, void *data)
392 {
393         atomic_t *atm = data;
394         int val = 0;
395         int rc;
396         
397         rc = lprocfs_write_helper(buffer, count, &val);
398         if (rc < 0)
399                 return rc;
400
401         if (val <= 0)
402                 return -ERANGE;
403                 
404         atomic_set(atm, val);
405         return count;
406 }
407
408 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
409                     int *eof, void *data)
410 {
411         struct obd_device *obd = (struct obd_device*)data;
412
413         LASSERT(obd != NULL);
414         *eof = 1;
415         return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
416 }
417
418 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
419                     int *eof, void* data)
420 {
421         struct obd_device *dev = (struct obd_device *)data;
422
423         LASSERT(dev != NULL);
424         LASSERT(dev->obd_name != NULL);
425         *eof = 1;
426         return snprintf(page, count, "%s\n", dev->obd_name);
427 }
428
429 int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
430                       void *data)
431 {
432         struct obd_device *obd = (struct obd_device *)data;
433
434         LASSERT(obd != NULL);
435         LASSERT(obd->obd_fsops != NULL);
436         LASSERT(obd->obd_fsops->fs_type != NULL);
437         return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
438 }
439
440 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
441                        int *eof, void *data)
442 {
443         struct obd_statfs osfs;
444         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
445                             OBD_STATFS_NODELAY);
446         if (!rc) {
447                 *eof = 1;
448                 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
449         }
450         return rc;
451 }
452
453 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
454                            int *eof, void *data)
455 {
456         struct obd_statfs osfs;
457         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
458                             OBD_STATFS_NODELAY);
459         if (!rc) {
460                 __u32 blk_size = osfs.os_bsize >> 10;
461                 __u64 result = osfs.os_blocks;
462
463                 while (blk_size >>= 1)
464                         result <<= 1;
465
466                 *eof = 1;
467                 rc = snprintf(page, count, LPU64"\n", result);
468         }
469         return rc;
470 }
471
472 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
473                           int *eof, void *data)
474 {
475         struct obd_statfs osfs;
476         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
477                             OBD_STATFS_NODELAY);
478         if (!rc) {
479                 __u32 blk_size = osfs.os_bsize >> 10;
480                 __u64 result = osfs.os_bfree;
481
482                 while (blk_size >>= 1)
483                         result <<= 1;
484
485                 *eof = 1;
486                 rc = snprintf(page, count, LPU64"\n", result);
487         }
488         return rc;
489 }
490
491 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
492                            int *eof, void *data)
493 {
494         struct obd_statfs osfs;
495         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
496                             OBD_STATFS_NODELAY);
497         if (!rc) {
498                 __u32 blk_size = osfs.os_bsize >> 10;
499                 __u64 result = osfs.os_bavail;
500
501                 while (blk_size >>= 1)
502                         result <<= 1;
503
504                 *eof = 1;
505                 rc = snprintf(page, count, LPU64"\n", result);
506         }
507         return rc;
508 }
509
510 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
511                           int *eof, void *data)
512 {
513         struct obd_statfs osfs;
514         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
515                             OBD_STATFS_NODELAY);
516         if (!rc) {
517                 *eof = 1;
518                 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
519         }
520
521         return rc;
522 }
523
524 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
525                          int *eof, void *data)
526 {
527         struct obd_statfs osfs;
528         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
529                             OBD_STATFS_NODELAY);
530         if (!rc) {
531                 *eof = 1;
532                 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
533         }
534         return rc;
535 }
536
537 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
538                            int *eof, void *data)
539 {
540         struct obd_device *obd = (struct obd_device *)data;
541         struct obd_import *imp;
542         char *imp_state_name = NULL;
543         int rc = 0;
544
545         LASSERT(obd != NULL);
546         LPROCFS_CLIMP_CHECK(obd);
547         imp = obd->u.cli.cl_import;
548         imp_state_name = ptlrpc_import_state_name(imp->imp_state);
549         *eof = 1;
550         rc = snprintf(page, count, "%s\t%s%s\n",
551                       obd2cli_tgt(obd), imp_state_name,
552                       imp->imp_deactive ? "\tDEACTIVATED" : "");
553
554         LPROCFS_CLIMP_EXIT(obd);
555         return rc;
556 }
557
558 int lprocfs_rd_conn_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 ptlrpc_connection *conn;
563         int rc = 0;
564
565         LASSERT(obd != NULL);
566
567         LPROCFS_CLIMP_CHECK(obd);
568         conn = obd->u.cli.cl_import->imp_connection;
569         LASSERT(conn != NULL);
570         *eof = 1;
571         if (obd->u.cli.cl_import) {
572                 rc = snprintf(page, count, "%s\n",
573                               conn->c_remote_uuid.uuid);
574         } else {
575                 rc = snprintf(page, count, "%s\n", "<none>");
576         }
577
578         LPROCFS_CLIMP_EXIT(obd);
579         return rc;
580 }
581
582 static const char *obd_connect_names[] = {
583         "read_only",
584         "lov_index",
585         "unused",
586         "write_grant",
587         "server_lock",
588         "version",
589         "request_portal",
590         "acl",
591         "xattr",
592         "create_on_write",
593         "truncate_lock",
594         "initial_transno",
595         "inode_bit_locks",
596         "join_file",
597         "getattr_by_fid",
598         "no_oh_for_devices",
599         "local_client",
600         "remote_client",
601         "max_byte_per_rpc",
602         "64bit_qdata",
603         "mds_capability",
604         "oss_capability",
605         "early_lock_cancel",
606         "size_on_mds",
607         "adaptive_timeouts",
608         "lru_resize",
609         "mds_mds_connection",
610         "real_conn",
611         "change_qunit_size",
612         "alt_checksum_algorithm",
613         "fid_is_enabled",
614         NULL
615 };
616
617 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
618                              int count, int *eof, void *data)
619 {
620         struct obd_device *obd = data;
621         __u64 mask = 1, flags;
622         int i, ret = 0;
623
624         LPROCFS_CLIMP_CHECK(obd);
625         flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
626         ret = snprintf(page, count, "flags="LPX64"\n", flags);
627         for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
628                 if (flags & mask)
629                         ret += snprintf(page + ret, count - ret, "%s\n",
630                                         obd_connect_names[i]);
631         }
632         if (flags & ~(mask - 1))
633                 ret += snprintf(page + ret, count - ret,
634                                 "unknown flags "LPX64"\n", flags & ~(mask - 1));
635
636         LPROCFS_CLIMP_EXIT(obd);
637         return ret;
638 }
639 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
640
641 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
642                            int *eof,  void *data)
643 {
644         struct obd_device *obd = (struct obd_device*)data;
645
646         LASSERT(obd != NULL);
647         *eof = 1;
648         return snprintf(page, count, "%u\n", obd->obd_num_exports);
649 }
650
651 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
652                        int *eof, void *data)
653 {
654         struct obd_type *class = (struct obd_type*) data;
655
656         LASSERT(class != NULL);
657         *eof = 1;
658         return snprintf(page, count, "%d\n", class->typ_refcnt);
659 }
660
661 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
662 {
663         int rc = 0;
664
665         LASSERT(obd != NULL);
666         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
667         LASSERT(obd->obd_type->typ_procroot != NULL);
668
669         obd->obd_proc_entry = lprocfs_register(obd->obd_name,
670                                                obd->obd_type->typ_procroot,
671                                                list, obd);
672         if (IS_ERR(obd->obd_proc_entry)) {
673                 rc = PTR_ERR(obd->obd_proc_entry);
674                 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
675                 obd->obd_proc_entry = NULL;
676         }
677         return rc;
678 }
679
680 int lprocfs_obd_cleanup(struct obd_device *obd)
681 {
682         if (!obd) 
683                 return -EINVAL;
684         if (obd->obd_proc_exports_entry) {
685                 /* Should be no exports left */
686                 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
687                 lprocfs_remove(&obd->obd_proc_exports_entry);
688         }
689         lprocfs_remove(&obd->obd_proc_entry);
690         return 0;
691 }
692
693 void lprocfs_free_client_stats(void *obj, void *data)
694 {
695         struct nid_stat *client_stat = obj;
696
697         CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
698                client_stat->nid_proc, client_stat->nid_stats,
699                client_stat->nid_brw_stats);
700
701         LASSERTF(client_stat->nid_exp_ref_count == 0, "count %d\n",
702                  client_stat->nid_exp_ref_count);
703
704         hlist_del_init(&client_stat->nid_hash);
705         list_del(&client_stat->nid_list);
706
707         if (client_stat->nid_proc)
708                 lprocfs_remove(&client_stat->nid_proc);
709
710         if (client_stat->nid_stats)
711                 lprocfs_free_stats(&client_stat->nid_stats);
712
713         if (client_stat->nid_brw_stats)
714                 OBD_FREE(client_stat->nid_brw_stats, sizeof(struct brw_stats));
715
716         OBD_FREE(client_stat, sizeof(*client_stat));
717         return;
718
719 }
720
721 void lprocfs_free_per_client_stats(struct obd_device *obd)
722 {
723         struct nid_stat *stat;
724         ENTRY;
725
726         /* we need extra list - because hash_exit called to early */
727         while(!list_empty(&obd->obd_nid_stats)) {
728                 stat = list_entry(obd->obd_nid_stats.next,
729                                   struct nid_stat, nid_list);
730                 lprocfs_free_client_stats(stat, NULL);
731         }
732
733         EXIT;
734 }
735
736 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
737                                           enum lprocfs_stats_flags flags)
738 {
739         struct lprocfs_stats *stats;
740         struct lprocfs_percpu *percpu;
741         unsigned int percpusize;
742         unsigned int i;
743         unsigned int num_cpu;
744
745         if (num == 0)
746                 return NULL;
747
748         if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
749                 num_cpu = 1;
750         else
751                 num_cpu = num_possible_cpus();
752
753         OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
754         if (stats == NULL)
755                 return NULL;
756
757         if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
758                 stats->ls_flags = flags;
759                 spin_lock_init(&stats->ls_lock);
760                 /* Use this lock only if there are no percpu areas */
761         } else {
762                 stats->ls_flags = 0;
763         }
764
765         percpusize = offsetof(typeof(*percpu), lp_cntr[num]);
766         if (num_cpu > 1)
767                 percpusize = L1_CACHE_ALIGN(percpusize);
768
769         stats->ls_percpu_size = num_cpu * percpusize;
770         OBD_ALLOC(stats->ls_percpu[0], stats->ls_percpu_size);
771         if (stats->ls_percpu[0] == NULL) {
772                 OBD_FREE(stats, offsetof(typeof(*stats),
773                                          ls_percpu[num_cpu]));
774                 return NULL;
775         }
776
777         stats->ls_num = num;
778         for (i = 1; i < num_cpu; i++)
779                 stats->ls_percpu[i] = (void *)(stats->ls_percpu[i - 1]) +
780                         percpusize;
781
782         return stats;
783 }
784
785 void lprocfs_free_stats(struct lprocfs_stats **statsh)
786 {
787         struct lprocfs_stats *stats = *statsh;
788         unsigned int num_cpu;
789
790         if (stats == NULL || stats->ls_num == 0)
791                 return;
792         *statsh = NULL;
793
794         if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
795                 num_cpu = 1;
796         else
797                 num_cpu = num_possible_cpus();
798
799         OBD_FREE(stats->ls_percpu[0], stats->ls_percpu_size);
800         OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
801 }
802
803 void lprocfs_clear_stats(struct lprocfs_stats *stats)
804 {
805         struct lprocfs_counter *percpu_cntr;
806         int i,j;
807         unsigned int num_cpu;
808
809         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
810
811         for (i = 0; i < num_cpu; i++) {
812                 for (j = 0; j < stats->ls_num; j++) {
813                         percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
814                         atomic_inc(&percpu_cntr->lc_cntl.la_entry);
815                         percpu_cntr->lc_count = 0;
816                         percpu_cntr->lc_sum = 0;
817                         percpu_cntr->lc_min = ~(__u64)0;
818                         percpu_cntr->lc_max = 0;
819                         percpu_cntr->lc_sumsquare = 0;
820                         atomic_inc(&percpu_cntr->lc_cntl.la_exit);
821                 }
822         }
823
824         lprocfs_stats_unlock(stats);
825 }
826
827 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
828                                        size_t len, loff_t *off)
829 {
830         struct seq_file *seq = file->private_data;
831         struct lprocfs_stats *stats = seq->private;
832
833         lprocfs_clear_stats(stats);
834
835         return len;
836 }
837
838 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
839 {
840         struct lprocfs_stats *stats = p->private;
841         /* return 1st cpu location */
842         return (*pos >= stats->ls_num) ? NULL :
843                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
844 }
845
846 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
847 {
848 }
849
850 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
851 {
852         struct lprocfs_stats *stats = p->private;
853         ++*pos;
854         return (*pos >= stats->ls_num) ? NULL :
855                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
856 }
857
858 /* seq file export of one lprocfs counter */
859 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
860 {
861        struct lprocfs_stats *stats = p->private;
862        struct lprocfs_counter  *cntr = v;
863        struct lprocfs_counter  t, ret = { .lc_min = ~(__u64)0 };
864        int i, idx, rc;
865        unsigned int num_cpu;
866
867        if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
868                struct timeval now;
869                do_gettimeofday(&now);
870                rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
871                                "snapshot_time", now.tv_sec, now.tv_usec);
872                if (rc < 0)
873                        return rc;
874        }
875        idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
876
877        if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
878                num_cpu = 1;
879        else
880                num_cpu = num_possible_cpus();
881
882        for (i = 0; i < num_cpu; i++) {
883                struct lprocfs_counter *percpu_cntr =
884                        &(stats->ls_percpu[i])->lp_cntr[idx];
885                int centry;
886
887                do {
888                        centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
889                        t.lc_count = percpu_cntr->lc_count;
890                        t.lc_sum = percpu_cntr->lc_sum;
891                        t.lc_min = percpu_cntr->lc_min;
892                        t.lc_max = percpu_cntr->lc_max;
893                        t.lc_sumsquare = percpu_cntr->lc_sumsquare;
894                } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
895                         centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
896                ret.lc_count += t.lc_count;
897                ret.lc_sum += t.lc_sum;
898                if (t.lc_min < ret.lc_min)
899                        ret.lc_min = t.lc_min;
900                if (t.lc_max > ret.lc_max)
901                        ret.lc_max = t.lc_max;
902                ret.lc_sumsquare += t.lc_sumsquare;
903        }
904
905        rc = seq_printf(p, "%-25s "LPU64" samples [%s]", cntr->lc_name,
906                        ret.lc_count, cntr->lc_units);
907        if (rc < 0)
908                goto out;
909
910        if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
911                rc = seq_printf(p, " "LPU64" "LPU64" "LPU64,
912                                ret.lc_min, ret.lc_max, ret.lc_sum);
913                if (rc < 0)
914                        goto out;
915                if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
916                        rc = seq_printf(p, " "LPU64, ret.lc_sumsquare);
917                if (rc < 0)
918                        goto out;
919        }
920        rc = seq_printf(p, "\n");
921  out:
922        return (rc < 0) ? rc : 0;
923 }
924
925 struct seq_operations lprocfs_stats_seq_sops = {
926         start: lprocfs_stats_seq_start,
927         stop:  lprocfs_stats_seq_stop,
928         next:  lprocfs_stats_seq_next,
929         show:  lprocfs_stats_seq_show,
930 };
931
932 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
933 {
934         struct proc_dir_entry *dp = PDE(inode);
935         struct seq_file *seq;
936         int rc;
937
938         LPROCFS_ENTRY_AND_CHECK(dp);
939         rc = seq_open(file, &lprocfs_stats_seq_sops);
940         if (rc) {
941                 LPROCFS_EXIT();
942                 return rc;
943         }
944         seq = file->private_data;
945         seq->private = dp->data;
946         return 0;
947 }
948
949 struct file_operations lprocfs_stats_seq_fops = {
950         .owner   = THIS_MODULE,
951         .open    = lprocfs_stats_seq_open,
952         .read    = seq_read,
953         .write   = lprocfs_stats_seq_write,
954         .llseek  = seq_lseek,
955         .release = lprocfs_seq_release,
956 };
957
958 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
959                            struct lprocfs_stats *stats)
960 {
961         struct proc_dir_entry *entry;
962         LASSERT(root != NULL);
963
964         entry = create_proc_entry(name, 0644, root);
965         if (entry == NULL)
966                 return -ENOMEM;
967         entry->proc_fops = &lprocfs_stats_seq_fops;
968         entry->data = (void *)stats;
969         return 0;
970 }
971
972 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
973                           unsigned conf, const char *name, const char *units)
974 {
975         struct lprocfs_counter *c;
976         int i;
977         unsigned int num_cpu;
978
979         LASSERT(stats != NULL);
980
981         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
982
983         for (i = 0; i < num_cpu; i++) {
984                 c = &(stats->ls_percpu[i]->lp_cntr[index]);
985                 c->lc_config = conf;
986                 c->lc_count = 0;
987                 c->lc_sum = 0;
988                 c->lc_min = ~(__u64)0;
989                 c->lc_max = 0;
990                 c->lc_name = name;
991                 c->lc_units = units;
992         }
993
994         lprocfs_stats_unlock(stats);
995 }
996 EXPORT_SYMBOL(lprocfs_counter_init);
997
998 #define LPROCFS_OBD_OP_INIT(base, stats, op)                               \
999 do {                                                                       \
1000         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);              \
1001         LASSERT(coffset < stats->ls_num);                                  \
1002         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");              \
1003 } while (0)
1004
1005 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1006 {
1007         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1008         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1009         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1010         LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1011         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1012         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1013         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1014         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1015         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1016         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1017         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1018         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1019         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1020         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1021         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1022         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1023         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1024         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1025         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1026         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1027         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1028         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1029         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1030         LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
1031         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1032         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1033         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1034         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1035         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1036         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1037         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1038         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1039         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1040         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
1041         LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
1042         LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
1043         LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
1044         LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
1045         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
1046         LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
1047         LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1048         LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1049         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1050         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1051         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1052         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1053         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1054         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1055         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1056         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1057         LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
1058         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1059         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1060         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1061         LPROCFS_OBD_OP_INIT(num_private_stats, stats, join_lru);
1062         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1063         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1064         LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1065         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1066         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1067         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1068         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1069         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1070         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1071         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1072         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1073         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1074         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1075         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1076 }
1077
1078 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1079 {
1080         struct lprocfs_stats *stats;
1081         unsigned int num_stats;
1082         int rc, i;
1083
1084         LASSERT(obd->obd_stats == NULL);
1085         LASSERT(obd->obd_proc_entry != NULL);
1086         LASSERT(obd->obd_cntr_base == 0);
1087
1088         num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1089                 num_private_stats - 1 /* o_owner */;
1090         stats = lprocfs_alloc_stats(num_stats, 0);
1091         if (stats == NULL)
1092                 return -ENOMEM;
1093
1094         lprocfs_init_ops_stats(num_private_stats, stats);
1095
1096         for (i = num_private_stats; i < num_stats; i++) {
1097                 /* If this LBUGs, it is likely that an obd
1098                  * operation was added to struct obd_ops in
1099                  * <obd.h>, and that the corresponding line item
1100                  * LPROCFS_OBD_OP_INIT(.., .., opname)
1101                  * is missing from the list above. */
1102                 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1103                          "Missing obd_stat initializer obd_op "
1104                          "operation at offset %d.\n", i - num_private_stats);
1105         }
1106         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1107         if (rc < 0) {
1108                 lprocfs_free_stats(&stats);
1109         } else {
1110                 obd->obd_stats  = stats;
1111                 obd->obd_cntr_base = num_private_stats;
1112         }
1113         return rc;
1114 }
1115
1116 void lprocfs_free_obd_stats(struct obd_device *obd)
1117 {
1118         if (obd->obd_stats) 
1119                 lprocfs_free_stats(&obd->obd_stats);
1120 }
1121
1122 #define LPROCFS_MD_OP_INIT(base, stats, op)                             \
1123 do {                                                                    \
1124         unsigned int coffset = base + MD_COUNTER_OFFSET(op);            \
1125         LASSERT(coffset < stats->ls_num);                               \
1126         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
1127 } while (0)
1128
1129 int lprocfs_alloc_md_stats(struct obd_device *obd,
1130                            unsigned num_private_stats)
1131 {
1132         struct lprocfs_stats *stats;
1133         unsigned int num_stats;
1134         int rc, i;
1135
1136         LASSERT(obd->md_stats == NULL);
1137         LASSERT(obd->obd_proc_entry != NULL);
1138         LASSERT(obd->md_cntr_base == 0);
1139
1140         num_stats = 1 + MD_COUNTER_OFFSET(get_remote_perm) +
1141                     num_private_stats;
1142         stats = lprocfs_alloc_stats(num_stats, 0);
1143         if (stats == NULL)
1144                 return -ENOMEM;
1145
1146         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1147         LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1148         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1149         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1150         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1151         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1152         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1153         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1154         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1155         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1156         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1157         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1158         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1159         LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1160         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1161         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1162         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1163         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1164         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1165         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1166         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1167         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1168         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1169         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1170         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1171         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1172         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1173         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1174
1175         for (i = num_private_stats; i < num_stats; i++) {
1176                 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1177                         CERROR("Missing md_stat initializer md_op "
1178                                "operation at offset %d. Aborting.\n",
1179                                i - num_private_stats);
1180                         LBUG();
1181                 }
1182         }
1183         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1184         if (rc < 0) {
1185                 lprocfs_free_stats(&stats);
1186         } else {
1187                 obd->md_stats  = stats;
1188                 obd->md_cntr_base = num_private_stats;
1189         }
1190         return rc;
1191 }
1192
1193 void lprocfs_free_md_stats(struct obd_device *obd)
1194 {
1195         struct lprocfs_stats *stats = obd->md_stats;
1196
1197         if (stats != NULL) {
1198                 obd->md_stats = NULL;
1199                 lprocfs_free_stats(&stats);
1200         }
1201 }
1202
1203 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1204                          int *eof,  void *data)
1205 {
1206         struct obd_export *exp = (struct obd_export*)data;
1207         LASSERT(exp != NULL);
1208         *eof = 1;
1209         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1210 }
1211
1212 struct exp_uuid_cb_data {
1213         char                   *page;
1214         int                     count;
1215         int                    *eof;
1216         int                    *len;
1217 };
1218
1219 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1220 {
1221         struct obd_export *exp = (struct obd_export *)obj;
1222         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1223
1224         if (exp->exp_nid_stats)
1225                 *data->len += snprintf((data->page + *data->len),
1226                                        data->count, "%s\n",
1227                                        obd_uuid2str(&exp->exp_client_uuid));
1228 }
1229
1230 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1231                         int *eof,  void *data)
1232 {
1233         struct nid_stat *stats = (struct nid_stat *)data;
1234         struct exp_uuid_cb_data cb_data;
1235         struct obd_device *obd = stats->nid_obd;
1236         int len = 0;
1237
1238         *eof = 1;
1239         page[0] = '\0';
1240         LASSERT(obd != NULL);
1241
1242         cb_data.page = page;
1243         cb_data.count = count;
1244         cb_data.eof = eof;
1245         cb_data.len = &len;
1246         lustre_hash_bucket_iterate(obd->obd_nid_hash_body,
1247                                    &stats->nid, lprocfs_exp_print_uuid,
1248                                    &cb_data);
1249         return (*cb_data.len);
1250 }
1251
1252 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1253                                         int count, int *eof,  void *data)
1254 {
1255         *eof = 1;
1256         return snprintf(page, count, "%s\n",
1257                         "Write into this file to clear all nid stats and "
1258                         "stale nid entries");
1259 }
1260 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1261
1262 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1263 {
1264         struct nid_stat *client_stat = obj;
1265         int i;
1266         if(client_stat->nid_exp_ref_count == 1) {
1267                 hlist_del_init(&client_stat->nid_hash);
1268                 lprocfs_free_client_stats(client_stat, data);
1269                 OBD_FREE(client_stat, sizeof(struct nid_stat));
1270                 EXIT;
1271                 return;
1272         }
1273
1274         /* we has reference to object - only clear data*/
1275         if (client_stat->nid_stats) {
1276                 lprocfs_clear_stats(client_stat->nid_stats);
1277         }
1278         if (client_stat->nid_brw_stats) {
1279                 for (i = 0; i < BRW_LAST; i++)
1280                         lprocfs_oh_clear(&client_stat->nid_brw_stats->hist[i]);
1281         }
1282         EXIT;
1283         return;
1284 }
1285
1286 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1287                                          unsigned long count, void *data)
1288 {
1289         struct obd_device *obd = (struct obd_device *)data;
1290         lustre_hash_iterate_all(obd->obd_nid_stats_hash_body,
1291                                 lprocfs_free_client_stats, NULL);
1292         return count;
1293 }
1294 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1295
1296 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1297 {
1298         int rc = 0;
1299         struct nid_stat *tmp = NULL, *tmp1;
1300         struct obd_device *obd = NULL;
1301         ENTRY;
1302
1303         *newnid = 0;
1304
1305         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1306             !exp->exp_obd->obd_nid_stats_hash_body)
1307                 RETURN(-EINVAL);
1308
1309         /* not test against zero because eric say:
1310          * You may only test nid against another nid, or LNET_NID_ANY.  Anything else is
1311          * nonsense.*/
1312         if (!nid || *nid == LNET_NID_ANY)
1313                 RETURN(0);
1314
1315         obd = exp->exp_obd;
1316
1317         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash_body);
1318
1319         OBD_ALLOC(tmp, sizeof(struct nid_stat));
1320         if (tmp == NULL)
1321                 RETURN(-ENOMEM);
1322
1323         tmp->nid = *nid;
1324         tmp->nid_obd = exp->exp_obd;
1325         tmp->nid_exp_ref_count = 1; /* need live in hash after destroy export */
1326
1327         tmp1= lustre_hash_findadd_unique(obd->obd_nid_stats_hash_body, nid,
1328                                          &tmp->nid_hash);
1329         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1330                tmp1, libcfs_nid2str(*nid), tmp->nid_exp_ref_count);
1331
1332         if (tmp1 != tmp) {
1333                 exp->exp_nid_stats = tmp1;
1334                 GOTO(destroy_new, rc = 0);
1335         }
1336         /* not found - create */
1337         tmp->nid_proc = proc_mkdir(libcfs_nid2str(*nid),
1338                                    obd->obd_proc_exports_entry);
1339         if (!tmp->nid_proc) {
1340                 CERROR("Error making export directory for"
1341                        " nid %s\n", libcfs_nid2str(*nid));
1342                 lustre_hash_delitem(obd->obd_nid_stats_hash_body, nid,
1343                                     &tmp->nid_hash);
1344                 GOTO(destroy_new, rc = -ENOMEM);
1345         }
1346
1347         rc = lprocfs_add_simple(tmp->nid_proc, "uuid",
1348                                 lprocfs_exp_rd_uuid, NULL, tmp);
1349         if (rc)
1350                 CWARN("Error adding the uuid file\n");
1351
1352         spin_lock(&obd->obd_nid_lock);
1353         list_add(&tmp->nid_list, &obd->obd_nid_stats);
1354         spin_unlock(&obd->obd_nid_lock);
1355
1356         exp->exp_nid_stats = tmp;
1357         *newnid = 1;
1358         RETURN(rc);
1359
1360 destroy_new:
1361         OBD_FREE(tmp, sizeof(struct nid_stat));
1362         RETURN(rc);
1363 }
1364
1365 int lprocfs_exp_cleanup(struct obd_export *exp)
1366 {
1367         struct nid_stat *stat = exp->exp_nid_stats;
1368
1369         if(!stat)
1370                 RETURN(0);
1371
1372         stat->nid_exp_ref_count--;
1373         CDEBUG(D_INFO, "Put stat %p - %d\n", stat, stat->nid_exp_ref_count);
1374
1375         exp->exp_nid_stats = NULL;
1376         return 0;
1377 }
1378
1379 int lprocfs_write_helper(const char *buffer, unsigned long count,
1380                          int *val)
1381 {
1382         return lprocfs_write_frac_helper(buffer, count, val, 1);
1383 }
1384
1385 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1386                               int *val, int mult)
1387 {
1388         char kernbuf[20], *end, *pbuf;
1389
1390         if (count > (sizeof(kernbuf) - 1))
1391                 return -EINVAL;
1392
1393         if (copy_from_user(kernbuf, buffer, count))
1394                 return -EFAULT;
1395
1396         kernbuf[count] = '\0';
1397         pbuf = kernbuf;
1398         if (*pbuf == '-') {
1399                 mult = -mult;
1400                 pbuf++;
1401         }
1402
1403         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1404         if (pbuf == end)
1405                 return -EINVAL;
1406
1407         if (end != NULL && *end == '.') {
1408                 int temp_val, pow = 1;
1409                 int i;
1410
1411                 pbuf = end + 1;
1412                 if (strlen(pbuf) > 5)
1413                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
1414
1415                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1416
1417                 if (pbuf < end) {
1418                         for (i = 0; i < (end - pbuf); i++)
1419                                 pow *= 10;
1420
1421                         *val += temp_val / pow;
1422                 }
1423         }
1424         return 0;
1425 }
1426
1427 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1428 {
1429         long decimal_val, frac_val;
1430         int prtn;
1431
1432         if (count < 10)
1433                 return -EINVAL;
1434
1435         decimal_val = val / mult;
1436         prtn = snprintf(buffer, count, "%ld", decimal_val);
1437         frac_val = val % mult;
1438
1439         if (prtn < (count - 4) && frac_val > 0) {
1440                 long temp_frac;
1441                 int i, temp_mult = 1, frac_bits = 0;
1442
1443                 temp_frac = frac_val * 10;
1444                 buffer[prtn++] = '.';
1445                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) { /*only reserved 2bits fraction*/
1446                         buffer[prtn++] ='0';
1447                         temp_frac *= 10;
1448                         frac_bits++;
1449                 }
1450                 /*
1451                   Need to think these cases :
1452                         1. #echo x.00 > /proc/xxx       output result : x
1453                         2. #echo x.0x > /proc/xxx       output result : x.0x
1454                         3. #echo x.x0 > /proc/xxx       output result : x.x
1455                         4. #echo x.xx > /proc/xxx       output result : x.xx
1456                         Only reserved 2bits fraction.       
1457                  */
1458                 for (i = 0; i < (5 - prtn); i++)
1459                         temp_mult *= 10;
1460
1461                 frac_bits = min((int)count - prtn, 3 - frac_bits);
1462                 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1463
1464                 prtn--;
1465                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1466                         prtn--;
1467                         if (buffer[prtn] == '.') {
1468                                 prtn--;
1469                                 break;
1470                         }
1471                 }
1472                 prtn++;
1473         }
1474         buffer[prtn++] ='\n';
1475         return prtn;
1476 }
1477
1478 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1479 {
1480         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1481 }
1482
1483 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1484                               __u64 *val, int mult)
1485 {
1486         char kernbuf[22], *end, *pbuf;
1487         __u64 whole, frac = 0, units;
1488         unsigned frac_d = 1;
1489
1490         if (count > (sizeof(kernbuf) - 1) )
1491                 return -EINVAL;
1492
1493         if (copy_from_user(kernbuf, buffer, count))
1494                 return -EFAULT;
1495
1496         kernbuf[count] = '\0';
1497         pbuf = kernbuf;
1498         if (*pbuf == '-') {
1499                 mult = -mult;
1500                 pbuf++;
1501         }
1502
1503         whole = simple_strtoull(pbuf, &end, 10);
1504         if (pbuf == end)
1505                 return -EINVAL;
1506
1507         if (end != NULL && *end == '.') {
1508                 int i;
1509                 pbuf = end + 1;
1510
1511                 /* need to limit frac_d to a __u32 */
1512                 if (strlen(pbuf) > 10)
1513                         pbuf[10] = '\0';
1514
1515                 frac = simple_strtoull(pbuf, &end, 10);
1516                 /* count decimal places */
1517                 for (i = 0; i < (end - pbuf); i++)
1518                         frac_d *= 10;
1519         }
1520
1521         units = 1;
1522         switch(*end) {
1523         case 'p': case 'P':
1524                 units <<= 10;
1525         case 't': case 'T':
1526                 units <<= 10;
1527         case 'g': case 'G':
1528                 units <<= 10;
1529         case 'm': case 'M':
1530                 units <<= 10;
1531         case 'k': case 'K':
1532                 units <<= 10;
1533         }
1534         /* Specified units override the multiplier */
1535         if (units) 
1536                 mult = mult < 0 ? -units : units;
1537
1538         frac *= mult;
1539         do_div(frac, frac_d);
1540         *val = whole * mult + frac;
1541         return 0;
1542 }
1543
1544 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, 
1545                        char *name, mode_t mode,
1546                        struct file_operations *seq_fops, void *data)
1547 {
1548         struct proc_dir_entry *entry;
1549         ENTRY;
1550
1551         entry = create_proc_entry(name, mode, parent);
1552         if (entry == NULL)
1553                 RETURN(-ENOMEM);
1554         entry->proc_fops = seq_fops;
1555         entry->data = data;
1556
1557         RETURN(0);
1558 }
1559 EXPORT_SYMBOL(lprocfs_seq_create);
1560
1561 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1562                                       mode_t mode,
1563                                       struct file_operations *seq_fops,
1564                                       void *data)
1565 {
1566         return (lprocfs_seq_create(dev->obd_proc_entry, name, 
1567                                    mode, seq_fops, data));
1568 }
1569 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1570
1571 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1572 {
1573         if (value >= OBD_HIST_MAX)
1574                 value = OBD_HIST_MAX - 1;
1575
1576         spin_lock(&oh->oh_lock);
1577         oh->oh_buckets[value]++;
1578         spin_unlock(&oh->oh_lock);
1579 }
1580 EXPORT_SYMBOL(lprocfs_oh_tally);
1581
1582 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1583 {
1584         unsigned int val;
1585
1586         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1587                 ;
1588
1589         lprocfs_oh_tally(oh, val);
1590 }
1591 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1592
1593 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1594 {
1595         unsigned long ret = 0;
1596         int i;
1597
1598         for (i = 0; i < OBD_HIST_MAX; i++)
1599                 ret +=  oh->oh_buckets[i];
1600         return ret;
1601 }
1602 EXPORT_SYMBOL(lprocfs_oh_sum);
1603
1604 void lprocfs_oh_clear(struct obd_histogram *oh)
1605 {
1606         spin_lock(&oh->oh_lock);
1607         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1608         spin_unlock(&oh->oh_lock);
1609 }
1610 EXPORT_SYMBOL(lprocfs_oh_clear);
1611
1612 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1613                                    int count, int *eof, void *data)
1614 {
1615         struct obd_device *obd = data;
1616         int len = 0, size;
1617
1618         LASSERT(obd != NULL);
1619         LASSERT(count >= 0);
1620
1621         /* Set start of user data returned to
1622            page + off since the user may have
1623            requested to read much smaller than
1624            what we need to read */
1625         *start = page + off;
1626
1627         /* We know we are allocated a page here.
1628            Also we know that this function will
1629            not need to write more than a page
1630            so we can truncate at CFS_PAGE_SIZE.  */
1631         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
1632
1633         /* Initialize the page */
1634         memset(page, 0, size);
1635
1636         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
1637                 goto out;
1638
1639         if (obd->obd_max_recoverable_clients == 0) {
1640                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
1641                         goto out;
1642
1643                 goto fclose;
1644         }
1645
1646         /* sampled unlocked, but really... */
1647         if (obd->obd_recovering == 0) {
1648                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
1649                         goto out;
1650
1651                 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1652                     obd->obd_recovery_start) <= 0)
1653                         goto out;
1654
1655                 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_end: %lu\n",
1656                     obd->obd_recovery_end) <= 0)
1657                         goto out;
1658
1659                 /* Number of clients have have completed recovery */
1660                 if (lprocfs_obd_snprintf(&page, size, &len, "recovered_clients: %d\n",
1661                     obd->obd_max_recoverable_clients - obd->obd_recoverable_clients) <= 0)
1662                         goto out;
1663
1664                 if (lprocfs_obd_snprintf(&page, size, &len, "unrecovered_clients: %d\n",
1665                     obd->obd_recoverable_clients) <= 0)
1666                         goto out;
1667
1668                 if (lprocfs_obd_snprintf(&page, size, &len, "last_transno: "LPD64"\n",
1669                     obd->obd_next_recovery_transno - 1) <= 0)
1670                         goto out;
1671
1672                 lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d\n", obd->obd_replayed_requests);
1673                 goto fclose;
1674         }
1675
1676         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
1677                 goto out;
1678
1679         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1680             obd->obd_recovery_start) <= 0)
1681                 goto out;
1682
1683         if (lprocfs_obd_snprintf(&page, size, &len, "time remaining: %lu\n",
1684                                  cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
1685                                  obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
1686                 goto out;
1687
1688         if(lprocfs_obd_snprintf(&page, size, &len, "connected_clients: %d/%d\n",
1689                                 obd->obd_connected_clients,
1690                                 obd->obd_max_recoverable_clients) <= 0)
1691                 goto out;
1692
1693         /* Number of clients have have completed recovery */
1694         if (lprocfs_obd_snprintf(&page, size, &len, "completed_clients: %d/%d\n",
1695                                  obd->obd_max_recoverable_clients - obd->obd_recoverable_clients,
1696                                  obd->obd_max_recoverable_clients) <= 0)
1697                 goto out;
1698
1699         if (lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d/??\n",
1700                                  obd->obd_replayed_requests) <= 0)
1701                 goto out;
1702
1703         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1704                                  obd->obd_requests_queued_for_recovery) <= 0)
1705                 goto out;
1706
1707         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n", 
1708                                  obd->obd_next_recovery_transno) <= 0)
1709                 goto out;
1710
1711 fclose:
1712         *eof = 1;
1713 out:
1714         return min(count, len - (int)off);
1715 }
1716 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1717
1718 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
1719                                     int count, int *eof, void *data)
1720 {
1721         struct obd_device *obd = (struct obd_device *)data;
1722         LASSERT(obd != NULL);
1723
1724         return snprintf(page, count, "%lu\n", 
1725                         obd->obd_recovery_max_time);
1726 }
1727 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
1728
1729 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
1730                                     unsigned long count, void *data)
1731 {
1732         struct obd_device *obd = (struct obd_device *)data;
1733         int val, rc;
1734         LASSERT(obd != NULL);
1735
1736         rc = lprocfs_write_helper(buffer, count, &val);
1737         if (rc)
1738                 return rc;
1739
1740         obd->obd_recovery_max_time = val;
1741         return count;
1742 }
1743 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
1744
1745 EXPORT_SYMBOL(lprocfs_register);
1746 EXPORT_SYMBOL(lprocfs_srch);
1747 EXPORT_SYMBOL(lprocfs_remove);
1748 EXPORT_SYMBOL(lprocfs_add_vars);
1749 EXPORT_SYMBOL(lprocfs_obd_setup);
1750 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1751 EXPORT_SYMBOL(lprocfs_add_simple);
1752 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
1753 EXPORT_SYMBOL(lprocfs_alloc_stats);
1754 EXPORT_SYMBOL(lprocfs_free_stats);
1755 EXPORT_SYMBOL(lprocfs_clear_stats);
1756 EXPORT_SYMBOL(lprocfs_register_stats);
1757 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1758 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1759 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1760 EXPORT_SYMBOL(lprocfs_exp_setup);
1761 EXPORT_SYMBOL(lprocfs_exp_cleanup);
1762
1763 EXPORT_SYMBOL(lprocfs_rd_u64);
1764 EXPORT_SYMBOL(lprocfs_rd_atomic);
1765 EXPORT_SYMBOL(lprocfs_wr_atomic);
1766 EXPORT_SYMBOL(lprocfs_rd_uint);
1767 EXPORT_SYMBOL(lprocfs_wr_uint);
1768 EXPORT_SYMBOL(lprocfs_rd_uuid);
1769 EXPORT_SYMBOL(lprocfs_rd_name);
1770 EXPORT_SYMBOL(lprocfs_rd_fstype);
1771 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
1772 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
1773 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1774 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1775
1776 EXPORT_SYMBOL(lprocfs_rd_blksize);
1777 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
1778 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
1779 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
1780 EXPORT_SYMBOL(lprocfs_rd_filestotal);
1781 EXPORT_SYMBOL(lprocfs_rd_filesfree);
1782
1783 EXPORT_SYMBOL(lprocfs_write_helper);
1784 EXPORT_SYMBOL(lprocfs_write_frac_helper);
1785 EXPORT_SYMBOL(lprocfs_read_frac_helper);
1786 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1787 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
1788 #endif /* LPROCFS*/