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