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