1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 only,
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License version 2 for more details (a copy is included
16 * in the LICENSE file that accompanied this code).
18 * You should have received a copy of the GNU General Public License
19 * version 2 along with this program; If not, see
20 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
22 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23 * CA 95054 USA or visit www.sun.com if you need additional information or
29 * Copyright 2008 Sun Microsystems, Inc. All rights reserved
30 * Use is subject to license terms.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
36 * lustre/obdclass/lprocfs_status.c
38 * Author: Hariharan Thantry <thantry@users.sourceforge.net>
42 # define EXPORT_SYMTAB
44 #define DEBUG_SUBSYSTEM S_CLASS
47 # include <liblustre.h>
50 #include <obd_class.h>
51 #include <lprocfs_status.h>
52 #include <lustre_fsfilt.h>
53 #include <lustre_log.h>
54 #include <lustre/lustre_idl.h>
58 #define MAX_STRING_SIZE 128
60 /* for bug 10866, global variable */
61 DECLARE_RWSEM(_lprocfs_lock);
62 EXPORT_SYMBOL(_lprocfs_lock);
64 int lprocfs_seq_release(struct inode *inode, struct file *file)
67 return seq_release(inode, file);
69 EXPORT_SYMBOL(lprocfs_seq_release);
71 struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
74 struct proc_dir_entry *temp;
81 while (temp != NULL) {
82 if (strcmp(temp->name, name) == 0) {
93 /* lprocfs API calls */
95 /* Function that emulates snprintf but also has the side effect of advancing
96 the page pointer for the next write into the buffer, incrementing the total
97 length written to the buffer, and decrementing the size left in the
99 static int lprocfs_obd_snprintf(char **page, int end, int *len,
100 const char *format, ...)
108 va_start(list, format);
109 n = vsnprintf(*page, end - *len, format, list);
112 *page += n; *len += n;
116 cfs_proc_dir_entry_t *lprocfs_add_simple(struct proc_dir_entry *root,
118 read_proc_t *read_proc,
119 write_proc_t *write_proc,
121 struct file_operations *fops)
123 cfs_proc_dir_entry_t *proc;
126 if (root == NULL || name == NULL)
127 return ERR_PTR(-EINVAL);
134 proc = create_proc_entry(name, mode, root);
136 CERROR("LprocFS: No memory to create /proc entry %s", name);
137 return ERR_PTR(-ENOMEM);
139 proc->read_proc = read_proc;
140 proc->write_proc = write_proc;
143 proc->proc_fops = fops;
147 struct proc_dir_entry *lprocfs_add_symlink(const char *name,
148 struct proc_dir_entry *parent, const char *dest)
150 struct proc_dir_entry *entry;
152 if (parent == NULL || dest == NULL)
155 entry = proc_symlink(name, parent, dest);
157 CERROR("LprocFS: Could not create symbolic link from %s to %s",
162 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
163 size_t size, loff_t *ppos)
165 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
166 char *page, *start = NULL;
167 int rc = 0, eof = 1, count;
169 if (*ppos >= CFS_PAGE_SIZE)
172 page = (char *)__get_free_page(GFP_KERNEL);
177 OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
178 if (!dp->deleted && dp->read_proc)
179 rc = dp->read_proc(page, &start, *ppos, CFS_PAGE_SIZE,
185 /* for lustre proc read, the read count must be less than PAGE_SIZE */
194 start = page + *ppos;
195 } else if (start < page) {
199 count = (rc < size) ? rc : size;
200 if (copy_to_user(buf, start, count)) {
207 free_page((unsigned long)page);
211 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf,
212 size_t size, loff_t *ppos)
214 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
218 if (!dp->deleted && dp->write_proc)
219 rc = dp->write_proc(f, buf, size, dp->data);
224 static struct file_operations lprocfs_generic_fops = {
225 .owner = THIS_MODULE,
226 .read = lprocfs_fops_read,
227 .write = lprocfs_fops_write,
230 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
232 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
233 struct obd_device *obd = dp->data;
235 atomic_inc(&obd->obd_evict_inprogress);
240 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
242 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
243 struct obd_device *obd = dp->data;
245 atomic_dec(&obd->obd_evict_inprogress);
246 wake_up(&obd->obd_evict_inprogress_waitq);
251 struct file_operations lprocfs_evict_client_fops = {
252 .owner = THIS_MODULE,
253 .read = lprocfs_fops_read,
254 .write = lprocfs_fops_write,
255 .open = lprocfs_evict_client_open,
256 .release = lprocfs_evict_client_release,
258 EXPORT_SYMBOL(lprocfs_evict_client_fops);
263 * \param root [in] The parent proc entry on which new entry will be added.
264 * \param list [in] Array of proc entries to be added.
265 * \param data [in] The argument to be passed when entries read/write routines
266 * are called through /proc file.
268 * \retval 0 on success
271 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
274 if (root == NULL || list == NULL)
277 while (list->name != NULL) {
278 struct proc_dir_entry *cur_root, *proc;
279 char *pathcopy, *cur, *next, pathbuf[64];
280 int pathsize = strlen(list->name) + 1;
285 /* need copy of path for strsep */
286 if (strlen(list->name) > sizeof(pathbuf) - 1) {
287 OBD_ALLOC(pathcopy, pathsize);
288 if (pathcopy == NULL)
295 strcpy(pathcopy, list->name);
297 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
298 if (*cur =='\0') /* skip double/trailing "/" */
301 proc = lprocfs_srch(cur_root, cur);
302 CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
303 cur_root->name, cur, next,
304 (proc ? "exists" : "new"));
306 cur_root = (proc ? proc :
307 proc_mkdir(cur, cur_root));
308 } else if (proc == NULL) {
310 if (list->proc_mode != 0000) {
311 mode = list->proc_mode;
315 if (list->write_fptr)
318 proc = create_proc_entry(cur, mode, cur_root);
322 if (pathcopy != pathbuf)
323 OBD_FREE(pathcopy, pathsize);
325 if (cur_root == NULL || proc == NULL) {
326 CERROR("LprocFS: No memory to create /proc entry %s",
332 proc->proc_fops = list->fops;
334 proc->proc_fops = &lprocfs_generic_fops;
335 proc->read_proc = list->read_fptr;
336 proc->write_proc = list->write_fptr;
337 proc->data = (list->data ? list->data : data);
343 void lprocfs_remove(struct proc_dir_entry **rooth)
345 struct proc_dir_entry *root = *rooth;
346 struct proc_dir_entry *temp = root;
347 struct proc_dir_entry *rm_entry;
348 struct proc_dir_entry *parent;
354 parent = root->parent;
355 LASSERT(parent != NULL);
356 LPROCFS_WRITE_ENTRY(); /* search vs remove race */
359 while (temp->subdir != NULL)
365 /* Memory corruption once caused this to fail, and
366 without this LASSERT we would loop here forever. */
367 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
368 "0x%p %s/%s len %d\n", rm_entry, temp->name,
369 rm_entry->name, (int)strlen(rm_entry->name));
371 /* Now, the rm_entry->deleted flags is protected
372 * by _lprocfs_lock. */
373 rm_entry->data = NULL;
374 remove_proc_entry(rm_entry->name, temp);
378 LPROCFS_WRITE_EXIT();
381 void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
383 LASSERT(parent != NULL);
384 remove_proc_entry(name, parent);
387 struct proc_dir_entry *lprocfs_register(const char *name,
388 struct proc_dir_entry *parent,
389 struct lprocfs_vars *list, void *data)
391 struct proc_dir_entry *newchild;
393 newchild = lprocfs_srch(parent, name);
394 if (newchild != NULL) {
395 CERROR(" Lproc: Attempting to register %s more than once \n",
397 return ERR_PTR(-EALREADY);
400 newchild = proc_mkdir(name, parent);
401 if (newchild != NULL && list != NULL) {
402 int rc = lprocfs_add_vars(newchild, list, data);
404 lprocfs_remove(&newchild);
411 /* Generic callbacks */
412 int lprocfs_rd_uint(char *page, char **start, off_t off,
413 int count, int *eof, void *data)
415 unsigned int *temp = data;
416 return snprintf(page, count, "%u\n", *temp);
419 int lprocfs_wr_uint(struct file *file, const char *buffer,
420 unsigned long count, void *data)
423 char dummy[MAX_STRING_SIZE + 1], *end;
426 dummy[MAX_STRING_SIZE] = '\0';
427 if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))
430 tmp = simple_strtoul(dummy, &end, 0);
434 *p = (unsigned int)tmp;
438 int lprocfs_rd_u64(char *page, char **start, off_t off,
439 int count, int *eof, void *data)
441 LASSERT(data != NULL);
443 return snprintf(page, count, LPU64"\n", *(__u64 *)data);
446 int lprocfs_rd_atomic(char *page, char **start, off_t off,
447 int count, int *eof, void *data)
449 atomic_t *atom = data;
450 LASSERT(atom != NULL);
452 return snprintf(page, count, "%d\n", atomic_read(atom));
455 int lprocfs_wr_atomic(struct file *file, const char *buffer,
456 unsigned long count, void *data)
458 atomic_t *atm = data;
462 rc = lprocfs_write_helper(buffer, count, &val);
469 atomic_set(atm, val);
473 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
474 int *eof, void *data)
476 struct obd_device *obd = data;
478 LASSERT(obd != NULL);
480 return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
483 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
484 int *eof, void *data)
486 struct obd_device *dev = data;
488 LASSERT(dev != NULL);
489 LASSERT(dev->obd_name != NULL);
491 return snprintf(page, count, "%s\n", dev->obd_name);
494 int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
497 struct obd_device *obd = data;
499 LASSERT(obd != NULL);
500 LASSERT(obd->obd_fsops != NULL);
501 LASSERT(obd->obd_fsops->fs_type != NULL);
502 return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
505 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
506 int *eof, void *data)
508 struct obd_statfs osfs;
509 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
513 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
518 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
519 int *eof, void *data)
521 struct obd_statfs osfs;
522 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
525 __u32 blk_size = osfs.os_bsize >> 10;
526 __u64 result = osfs.os_blocks;
528 while (blk_size >>= 1)
532 rc = snprintf(page, count, LPU64"\n", result);
537 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
538 int *eof, void *data)
540 struct obd_statfs osfs;
541 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
544 __u32 blk_size = osfs.os_bsize >> 10;
545 __u64 result = osfs.os_bfree;
547 while (blk_size >>= 1)
551 rc = snprintf(page, count, LPU64"\n", result);
556 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
557 int *eof, void *data)
559 struct obd_statfs osfs;
560 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
563 __u32 blk_size = osfs.os_bsize >> 10;
564 __u64 result = osfs.os_bavail;
566 while (blk_size >>= 1)
570 rc = snprintf(page, count, LPU64"\n", result);
575 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
576 int *eof, void *data)
578 struct obd_statfs osfs;
579 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
583 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
589 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
590 int *eof, void *data)
592 struct obd_statfs osfs;
593 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
597 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
602 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
603 int *eof, void *data)
605 struct obd_device *obd = data;
606 struct obd_import *imp;
607 char *imp_state_name = NULL;
610 LASSERT(obd != NULL);
611 LPROCFS_CLIMP_CHECK(obd);
612 imp = obd->u.cli.cl_import;
613 imp_state_name = ptlrpc_import_state_name(imp->imp_state);
615 rc = snprintf(page, count, "%s\t%s%s\n",
616 obd2cli_tgt(obd), imp_state_name,
617 imp->imp_deactive ? "\tDEACTIVATED" : "");
619 LPROCFS_CLIMP_EXIT(obd);
623 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
624 int *eof, void *data)
626 struct obd_device *obd = data;
627 struct ptlrpc_connection *conn;
630 LASSERT(obd != NULL);
632 LPROCFS_CLIMP_CHECK(obd);
633 conn = obd->u.cli.cl_import->imp_connection;
634 LASSERT(conn != NULL);
636 if (obd->u.cli.cl_import) {
637 rc = snprintf(page, count, "%s\n",
638 conn->c_remote_uuid.uuid);
640 rc = snprintf(page, count, "%s\n", "<none>");
643 LPROCFS_CLIMP_EXIT(obd);
647 #define flag2str(flag) \
648 if (imp->imp_##flag && max - len > 0) \
649 len += snprintf(str + len, max - len, " " #flag);
652 * Append a space separated list of current set flags to str.
654 static int obd_import_flags2str(struct obd_import *imp, char *str,
659 if (imp->imp_obd->obd_no_recov)
660 len += snprintf(str, max - len, " no_recov");
664 flag2str(replayable);
667 flag2str(last_recon);
672 int lprocfs_rd_import(char *page, char **start, off_t off, int count,
673 int *eof, void *data)
675 struct obd_device *obd = (struct obd_device *)data;
676 struct obd_import *imp;
677 char *imp_state_name = NULL;
680 LASSERT(obd != NULL);
681 LPROCFS_CLIMP_CHECK(obd);
682 imp = obd->u.cli.cl_import;
683 imp_state_name = ptlrpc_import_state_name(imp->imp_state);
686 rc = snprintf(page, count,
691 " unregistering: %u\n"
695 " last_replay_transno: "LPU64"\n"
696 " peer_committed_transno: "LPU64"\n"
697 " last_trasno_checked: "LPU64"\n"
700 obd2cli_tgt(obd), imp->imp_connection->c_remote_uuid.uuid,
702 atomic_read(&imp->imp_inflight),
703 atomic_read(&imp->imp_unregistering),
706 atomic_read(&imp->imp_inval_count),
707 imp->imp_last_replay_transno,
708 imp->imp_peer_committed_transno,
709 imp->imp_last_transno_checked);
710 rc += obd_import_flags2str(imp, page + rc, count - rc);
711 rc += snprintf(page+rc, count - rc, "\n");
712 LPROCFS_CLIMP_EXIT(obd);
716 int lprocfs_at_hist_helper(char *page, int count, int rc,
717 struct adaptive_timeout *at)
720 for (i = 0; i < AT_BINS; i++)
721 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
722 rc += snprintf(page + rc, count - rc, "\n");
726 /* See also ptlrpc_lprocfs_rd_timeouts */
727 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
728 int *eof, void *data)
730 struct obd_device *obd = (struct obd_device *)data;
731 struct obd_import *imp;
732 unsigned int cur, worst;
737 LASSERT(obd != NULL);
738 LPROCFS_CLIMP_CHECK(obd);
739 imp = obd->u.cli.cl_import;
742 now = cfs_time_current_sec();
744 /* Some network health info for kicks */
745 s2dhms(&ts, now - imp->imp_last_reply_time);
746 rc += snprintf(page + rc, count - rc,
747 "%-10s : %ld, "DHMS_FMT" ago\n",
748 "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
750 cur = at_get(&imp->imp_at.iat_net_latency);
751 worst = imp->imp_at.iat_net_latency.at_worst_ever;
752 worstt = imp->imp_at.iat_net_latency.at_worst_time;
753 s2dhms(&ts, now - worstt);
754 rc += snprintf(page + rc, count - rc,
755 "%-10s : cur %3u worst %3u (at %ld, "DHMS_FMT" ago) ",
756 "network", cur, worst, worstt, DHMS_VARS(&ts));
757 rc = lprocfs_at_hist_helper(page, count, rc,
758 &imp->imp_at.iat_net_latency);
760 for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
761 if (imp->imp_at.iat_portal[i] == 0)
763 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
764 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
765 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
766 s2dhms(&ts, now - worstt);
767 rc += snprintf(page + rc, count - rc,
768 "portal %-2d : cur %3u worst %3u (at %ld, "
769 DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
770 cur, worst, worstt, DHMS_VARS(&ts));
771 rc = lprocfs_at_hist_helper(page, count, rc,
772 &imp->imp_at.iat_service_estimate[i]);
775 LPROCFS_CLIMP_EXIT(obd);
779 static const char *obd_connect_names[] = {
806 "mds_mds_connection",
809 "alt_checksum_algorithm",
813 "", /* reserved for simplified interop */
818 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
819 int count, int *eof, void *data)
821 struct obd_device *obd = data;
822 __u64 mask = 1, flags;
825 LPROCFS_CLIMP_CHECK(obd);
826 flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
827 ret = snprintf(page, count, "flags="LPX64"\n", flags);
828 for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
830 ret += snprintf(page + ret, count - ret, "%s\n",
831 obd_connect_names[i]);
833 if (flags & ~(mask - 1))
834 ret += snprintf(page + ret, count - ret,
835 "unknown flags "LPX64"\n", flags & ~(mask - 1));
837 LPROCFS_CLIMP_EXIT(obd);
840 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
842 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
843 int *eof, void *data)
845 struct obd_device *obd = data;
847 LASSERT(obd != NULL);
849 return snprintf(page, count, "%u\n", obd->obd_num_exports);
852 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
853 int *eof, void *data)
855 struct obd_type *class = (struct obd_type*) data;
857 LASSERT(class != NULL);
859 return snprintf(page, count, "%d\n", class->typ_refcnt);
862 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
866 LASSERT(obd != NULL);
867 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
868 LASSERT(obd->obd_type->typ_procroot != NULL);
870 obd->obd_proc_entry = lprocfs_register(obd->obd_name,
871 obd->obd_type->typ_procroot,
873 if (IS_ERR(obd->obd_proc_entry)) {
874 rc = PTR_ERR(obd->obd_proc_entry);
875 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
876 obd->obd_proc_entry = NULL;
881 int lprocfs_obd_cleanup(struct obd_device *obd)
885 if (obd->obd_proc_exports_entry) {
886 /* Should be no exports left */
887 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
888 lprocfs_remove(&obd->obd_proc_exports_entry);
889 obd->obd_proc_exports_entry = NULL;
891 if (obd->obd_proc_entry) {
892 lprocfs_remove(&obd->obd_proc_entry);
893 obd->obd_proc_entry = NULL;
898 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
900 CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
901 client_stat->nid_proc, client_stat->nid_stats,
902 client_stat->nid_brw_stats);
904 LASSERTF(client_stat->nid_exp_ref_count == 0, "count %d\n",
905 client_stat->nid_exp_ref_count);
907 hlist_del_init(&client_stat->nid_hash);
909 if (client_stat->nid_proc)
910 lprocfs_remove(&client_stat->nid_proc);
912 if (client_stat->nid_stats)
913 lprocfs_free_stats(&client_stat->nid_stats);
915 if (client_stat->nid_brw_stats)
916 OBD_FREE_PTR(client_stat->nid_brw_stats);
918 if (client_stat->nid_ldlm_stats)
919 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
921 OBD_FREE_PTR(client_stat);
926 void lprocfs_free_per_client_stats(struct obd_device *obd)
928 struct nid_stat *stat;
931 /* we need extra list - because hash_exit called to early */
932 /* not need locking because all clients is died */
933 while(!list_empty(&obd->obd_nid_stats)) {
934 stat = list_entry(obd->obd_nid_stats.next,
935 struct nid_stat, nid_list);
936 list_del_init(&stat->nid_list);
937 lprocfs_free_client_stats(stat);
943 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
944 enum lprocfs_stats_flags flags)
946 struct lprocfs_stats *stats;
947 unsigned int percpusize;
949 unsigned int num_cpu;
954 if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
957 num_cpu = num_possible_cpus();
959 OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
963 if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
964 stats->ls_flags = flags;
965 spin_lock_init(&stats->ls_lock);
966 /* Use this lock only if there are no percpu areas */
971 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
973 percpusize = L1_CACHE_ALIGN(percpusize);
975 for (i = 0; i < num_cpu; i++) {
976 OBD_ALLOC(stats->ls_percpu[i], percpusize);
977 if (stats->ls_percpu[i] == NULL) {
978 for (j = 0; j < i; j++) {
979 OBD_FREE(stats->ls_percpu[j], percpusize);
980 stats->ls_percpu[j] = NULL;
985 if (stats->ls_percpu[0] == NULL) {
986 OBD_FREE(stats, offsetof(typeof(*stats),
987 ls_percpu[num_cpu]));
995 void lprocfs_free_stats(struct lprocfs_stats **statsh)
997 struct lprocfs_stats *stats = *statsh;
998 unsigned int num_cpu;
999 unsigned int percpusize;
1002 if (stats == NULL || stats->ls_num == 0)
1006 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1009 num_cpu = num_possible_cpus();
1011 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
1013 percpusize = L1_CACHE_ALIGN(percpusize);
1014 for (i = 0; i < num_cpu; i++)
1015 OBD_FREE(stats->ls_percpu[i], percpusize);
1016 OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
1019 void lprocfs_clear_stats(struct lprocfs_stats *stats)
1021 struct lprocfs_counter *percpu_cntr;
1023 unsigned int num_cpu;
1025 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1027 for (i = 0; i < num_cpu; i++) {
1028 for (j = 0; j < stats->ls_num; j++) {
1029 percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
1030 atomic_inc(&percpu_cntr->lc_cntl.la_entry);
1031 percpu_cntr->lc_count = 0;
1032 percpu_cntr->lc_sum = 0;
1033 percpu_cntr->lc_min = LC_MIN_INIT;
1034 percpu_cntr->lc_max = 0;
1035 percpu_cntr->lc_sumsquare = 0;
1036 atomic_inc(&percpu_cntr->lc_cntl.la_exit);
1040 lprocfs_stats_unlock(stats);
1043 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
1044 size_t len, loff_t *off)
1046 struct seq_file *seq = file->private_data;
1047 struct lprocfs_stats *stats = seq->private;
1049 lprocfs_clear_stats(stats);
1054 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
1056 struct lprocfs_stats *stats = p->private;
1057 /* return 1st cpu location */
1058 return (*pos >= stats->ls_num) ? NULL :
1059 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1062 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1066 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1068 struct lprocfs_stats *stats = p->private;
1070 return (*pos >= stats->ls_num) ? NULL :
1071 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1074 /* seq file export of one lprocfs counter */
1075 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1077 struct lprocfs_stats *stats = p->private;
1078 struct lprocfs_counter *cntr = v;
1079 struct lprocfs_counter t, ret = { .lc_min = LC_MIN_INIT };
1081 unsigned int num_cpu;
1083 if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
1085 do_gettimeofday(&now);
1086 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1087 "snapshot_time", now.tv_sec, now.tv_usec);
1091 idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
1093 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1096 num_cpu = num_possible_cpus();
1098 for (i = 0; i < num_cpu; i++) {
1099 struct lprocfs_counter *percpu_cntr =
1100 &(stats->ls_percpu[i])->lp_cntr[idx];
1104 centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
1105 t.lc_count = percpu_cntr->lc_count;
1106 t.lc_sum = percpu_cntr->lc_sum;
1107 t.lc_min = percpu_cntr->lc_min;
1108 t.lc_max = percpu_cntr->lc_max;
1109 t.lc_sumsquare = percpu_cntr->lc_sumsquare;
1110 } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
1111 centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
1112 ret.lc_count += t.lc_count;
1113 ret.lc_sum += t.lc_sum;
1114 if (t.lc_min < ret.lc_min)
1115 ret.lc_min = t.lc_min;
1116 if (t.lc_max > ret.lc_max)
1117 ret.lc_max = t.lc_max;
1118 ret.lc_sumsquare += t.lc_sumsquare;
1121 if (ret.lc_count == 0)
1124 rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
1125 ret.lc_count, cntr->lc_units);
1129 if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
1130 rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1131 ret.lc_min, ret.lc_max, ret.lc_sum);
1134 if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
1135 rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1139 rc = seq_printf(p, "\n");
1141 return (rc < 0) ? rc : 0;
1144 struct seq_operations lprocfs_stats_seq_sops = {
1145 start: lprocfs_stats_seq_start,
1146 stop: lprocfs_stats_seq_stop,
1147 next: lprocfs_stats_seq_next,
1148 show: lprocfs_stats_seq_show,
1151 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1153 struct proc_dir_entry *dp = PDE(inode);
1154 struct seq_file *seq;
1157 LPROCFS_ENTRY_AND_CHECK(dp);
1158 rc = seq_open(file, &lprocfs_stats_seq_sops);
1163 seq = file->private_data;
1164 seq->private = dp->data;
1168 struct file_operations lprocfs_stats_seq_fops = {
1169 .owner = THIS_MODULE,
1170 .open = lprocfs_stats_seq_open,
1172 .write = lprocfs_stats_seq_write,
1173 .llseek = seq_lseek,
1174 .release = lprocfs_seq_release,
1177 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1178 struct lprocfs_stats *stats)
1180 struct proc_dir_entry *entry;
1181 LASSERT(root != NULL);
1183 entry = create_proc_entry(name, 0644, root);
1186 entry->proc_fops = &lprocfs_stats_seq_fops;
1187 entry->data = stats;
1191 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1192 unsigned conf, const char *name, const char *units)
1194 struct lprocfs_counter *c;
1196 unsigned int num_cpu;
1198 LASSERT(stats != NULL);
1200 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1202 for (i = 0; i < num_cpu; i++) {
1203 c = &(stats->ls_percpu[i]->lp_cntr[index]);
1204 c->lc_config = conf;
1207 c->lc_min = LC_MIN_INIT;
1210 c->lc_units = units;
1213 lprocfs_stats_unlock(stats);
1215 EXPORT_SYMBOL(lprocfs_counter_init);
1217 #define LPROCFS_OBD_OP_INIT(base, stats, op) \
1219 unsigned int coffset = base + OBD_COUNTER_OFFSET(op); \
1220 LASSERT(coffset < stats->ls_num); \
1221 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1224 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1226 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1227 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1228 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1229 LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1230 LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1231 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1232 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1233 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1234 LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1235 LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1236 LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1237 LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1238 LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1239 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1240 LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1241 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1242 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1243 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1244 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1245 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1246 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1247 LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1248 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1249 LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
1250 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1251 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1252 LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1253 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1254 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1255 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1256 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1257 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1258 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1259 LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1260 LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1261 LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1262 LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1263 LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1264 LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1265 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1266 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1267 LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1268 LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1269 LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1270 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1271 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1272 LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1273 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1274 LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1275 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1276 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1277 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1278 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1279 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1280 LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1281 LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1282 LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1283 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
1284 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1285 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1286 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quota_adjust_qunit);
1287 LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1288 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1289 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1290 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1291 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1294 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1296 struct lprocfs_stats *stats;
1297 unsigned int num_stats;
1300 LASSERT(obd->obd_stats == NULL);
1301 LASSERT(obd->obd_proc_entry != NULL);
1302 LASSERT(obd->obd_cntr_base == 0);
1304 num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1305 num_private_stats - 1 /* o_owner */;
1306 stats = lprocfs_alloc_stats(num_stats, 0);
1310 lprocfs_init_ops_stats(num_private_stats, stats);
1312 for (i = num_private_stats; i < num_stats; i++) {
1313 /* If this LBUGs, it is likely that an obd
1314 * operation was added to struct obd_ops in
1315 * <obd.h>, and that the corresponding line item
1316 * LPROCFS_OBD_OP_INIT(.., .., opname)
1317 * is missing from the list above. */
1318 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1319 "Missing obd_stat initializer obd_op "
1320 "operation at offset %d.\n", i - num_private_stats);
1322 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1324 lprocfs_free_stats(&stats);
1326 obd->obd_stats = stats;
1327 obd->obd_cntr_base = num_private_stats;
1332 void lprocfs_free_obd_stats(struct obd_device *obd)
1335 lprocfs_free_stats(&obd->obd_stats);
1338 #define LPROCFS_MD_OP_INIT(base, stats, op) \
1340 unsigned int coffset = base + MD_COUNTER_OFFSET(op); \
1341 LASSERT(coffset < stats->ls_num); \
1342 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1345 int lprocfs_alloc_md_stats(struct obd_device *obd,
1346 unsigned num_private_stats)
1348 struct lprocfs_stats *stats;
1349 unsigned int num_stats;
1352 LASSERT(obd->md_stats == NULL);
1353 LASSERT(obd->obd_proc_entry != NULL);
1354 LASSERT(obd->md_cntr_base == 0);
1356 num_stats = 1 + MD_COUNTER_OFFSET(revalidate_lock) +
1358 stats = lprocfs_alloc_stats(num_stats, 0);
1362 LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1363 LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1364 LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1365 LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1366 LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1367 LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1368 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1369 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1370 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1371 LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1372 LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1373 LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1374 LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1375 LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1376 LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1377 LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1378 LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1379 LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1380 LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1381 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1382 LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1383 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1384 LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1385 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1386 LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1387 LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1388 LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1389 LPROCFS_MD_OP_INIT(num_private_stats, stats, unpack_capa);
1390 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1391 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1392 LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1394 for (i = num_private_stats; i < num_stats; i++) {
1395 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1396 CERROR("Missing md_stat initializer md_op "
1397 "operation at offset %d. Aborting.\n",
1398 i - num_private_stats);
1402 rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
1404 lprocfs_free_stats(&stats);
1406 obd->md_stats = stats;
1407 obd->md_cntr_base = num_private_stats;
1412 void lprocfs_free_md_stats(struct obd_device *obd)
1414 struct lprocfs_stats *stats = obd->md_stats;
1416 if (stats != NULL) {
1417 obd->md_stats = NULL;
1418 obd->md_cntr_base = 0;
1419 lprocfs_free_stats(&stats);
1423 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1425 lprocfs_counter_init(ldlm_stats,
1426 LDLM_ENQUEUE - LDLM_FIRST_OPC,
1427 0, "ldlm_enqueue", "reqs");
1428 lprocfs_counter_init(ldlm_stats,
1429 LDLM_CONVERT - LDLM_FIRST_OPC,
1430 0, "ldlm_convert", "reqs");
1431 lprocfs_counter_init(ldlm_stats,
1432 LDLM_CANCEL - LDLM_FIRST_OPC,
1433 0, "ldlm_cancel", "reqs");
1434 lprocfs_counter_init(ldlm_stats,
1435 LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1436 0, "ldlm_bl_callback", "reqs");
1437 lprocfs_counter_init(ldlm_stats,
1438 LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1439 0, "ldlm_cp_callback", "reqs");
1440 lprocfs_counter_init(ldlm_stats,
1441 LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1442 0, "ldlm_gl_callback", "reqs");
1445 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1446 int *eof, void *data)
1448 struct obd_export *exp = data;
1449 LASSERT(exp != NULL);
1451 return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1454 struct exp_uuid_cb_data {
1462 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1463 int count, int *eof, int *len)
1465 cb_data->page = page;
1466 cb_data->count = count;
1471 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1473 struct obd_export *exp = (struct obd_export *)obj;
1474 struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1476 if (exp->exp_nid_stats)
1477 *data->len += snprintf((data->page + *data->len),
1478 data->count, "%s\n",
1479 obd_uuid2str(&exp->exp_client_uuid));
1482 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1483 int *eof, void *data)
1485 struct nid_stat *stats = (struct nid_stat *)data;
1486 struct exp_uuid_cb_data cb_data;
1487 struct obd_device *obd = stats->nid_obd;
1492 lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1493 lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1494 lprocfs_exp_print_uuid, &cb_data);
1495 return (*cb_data.len);
1498 void lprocfs_exp_print_hash(void *obj, void *cb_data)
1500 struct exp_uuid_cb_data *data = cb_data;
1501 struct obd_export *exp = obj;
1504 lh = exp->exp_lock_hash;
1507 *data->len += lustre_hash_debug_header(data->page,
1510 *data->len += lustre_hash_debug_str(lh, data->page + *data->len,
1515 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1516 int *eof, void *data)
1518 struct nid_stat *stats = (struct nid_stat *)data;
1519 struct exp_uuid_cb_data cb_data;
1520 struct obd_device *obd = stats->nid_obd;
1525 lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1527 lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1528 lprocfs_exp_print_hash, &cb_data);
1529 return (*cb_data.len);
1532 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1533 int count, int *eof, void *data)
1536 return snprintf(page, count, "%s\n",
1537 "Write into this file to clear all nid stats and "
1538 "stale nid entries");
1540 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1542 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1544 struct nid_stat *stat = obj;
1547 /* object has only hash + iterate_all references.
1548 * add/delete blocked by hash bucket lock */
1549 CDEBUG(D_INFO,"refcnt %d\n", stat->nid_exp_ref_count);
1550 if (stat->nid_exp_ref_count == 2) {
1551 hlist_del_init(&stat->nid_hash);
1552 stat->nid_exp_ref_count--;
1553 spin_lock(&stat->nid_obd->obd_nid_lock);
1554 list_move(&stat->nid_list, data);
1555 spin_unlock(&stat->nid_obd->obd_nid_lock);
1559 /* we has reference to object - only clear data*/
1560 if (stat->nid_stats)
1561 lprocfs_clear_stats(stat->nid_stats);
1563 if (stat->nid_brw_stats) {
1564 for (i = 0; i < BRW_LAST; i++)
1565 lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1571 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1572 unsigned long count, void *data)
1574 struct obd_device *obd = (struct obd_device *)data;
1575 struct nid_stat *client_stat;
1576 CFS_LIST_HEAD(free_list);
1578 lustre_hash_for_each(obd->obd_nid_stats_hash,
1579 lprocfs_nid_stats_clear_write_cb, &free_list);
1581 while (!list_empty(&free_list)) {
1582 client_stat = list_entry(free_list.next, struct nid_stat,
1584 list_del_init(&client_stat->nid_list);
1585 lprocfs_free_client_stats(client_stat);
1590 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1592 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1594 struct nid_stat *new_stat, *old_stat;
1595 struct nid_stat_uuid *new_ns_uuid;
1596 struct obd_device *obd = NULL;
1597 cfs_proc_dir_entry_t *entry;
1603 if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1604 !exp->exp_obd->obd_nid_stats_hash)
1607 /* not test against zero because eric say:
1608 * You may only test nid against another nid, or LNET_NID_ANY.
1609 * Anything else is nonsense.*/
1610 if (!nid || *nid == LNET_NID_ANY)
1615 CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1617 OBD_ALLOC_PTR(new_stat);
1618 if (new_stat == NULL)
1621 OBD_ALLOC_PTR(new_ns_uuid);
1622 if (new_ns_uuid == NULL) {
1623 OBD_FREE_PTR(new_stat);
1626 CFS_INIT_LIST_HEAD(&new_ns_uuid->ns_uuid_list);
1627 strncpy(new_ns_uuid->ns_uuid.uuid, exp->exp_client_uuid.uuid,
1628 sizeof(struct obd_uuid));
1630 CFS_INIT_LIST_HEAD(&new_stat->nid_uuid_list);
1631 new_stat->nid = *nid;
1632 new_stat->nid_obd = exp->exp_obd;
1633 new_stat->nid_exp_ref_count = 1; /* live in hash after destroy export */
1635 old_stat = lustre_hash_findadd_unique(obd->obd_nid_stats_hash,
1636 nid, &new_stat->nid_hash);
1637 CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1638 old_stat, libcfs_nid2str(*nid), new_stat->nid_exp_ref_count);
1640 /* Return -EALREADY here so that we know that the /proc
1641 * entry already has been created */
1642 if (old_stat != new_stat) {
1643 struct nid_stat_uuid *tmp_uuid;
1646 exp->exp_nid_stats = old_stat;
1647 /* We need to decrement the refcount if the uuid was
1648 * already in our list */
1649 spin_lock(&obd->obd_nid_lock);
1650 list_for_each_entry(tmp_uuid, &old_stat->nid_uuid_list,
1652 if (tmp_uuid && obd_uuid_equals(&tmp_uuid->ns_uuid,
1653 &exp->exp_client_uuid)){
1655 --old_stat->nid_exp_ref_count;
1661 list_add(&new_ns_uuid->ns_uuid_list,
1662 &old_stat->nid_uuid_list);
1664 OBD_FREE_PTR(new_ns_uuid);
1666 spin_unlock(&obd->obd_nid_lock);
1668 GOTO(destroy_new, rc = -EALREADY);
1670 /* not found - create */
1671 new_stat->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1672 obd->obd_proc_exports_entry,
1674 if (new_stat->nid_proc == NULL) {
1675 CERROR("Error making export directory for nid %s\n",
1676 libcfs_nid2str(*nid));
1677 GOTO(destroy_new_ns, rc = -ENOMEM);
1680 /* Add in uuid to our nid_stats list */
1681 spin_lock(&obd->obd_nid_lock);
1682 list_add(&new_ns_uuid->ns_uuid_list, &new_stat->nid_uuid_list);
1683 spin_unlock(&obd->obd_nid_lock);
1685 entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
1686 lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
1687 if (IS_ERR(entry)) {
1688 CWARN("Error adding the NID stats file\n");
1689 rc = PTR_ERR(entry);
1690 GOTO(destroy_new_ns, rc);
1693 entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
1694 lprocfs_exp_rd_hash, NULL, new_stat, NULL);
1695 if (IS_ERR(entry)) {
1696 CWARN("Error adding the hash file\n");
1697 rc = PTR_ERR(entry);
1698 GOTO(destroy_new_ns, rc);
1701 exp->exp_nid_stats = new_stat;
1703 /* protect competitive add to list, not need locking on destroy */
1704 spin_lock(&obd->obd_nid_lock);
1705 list_add(&new_stat->nid_list, &obd->obd_nid_stats);
1706 spin_unlock(&obd->obd_nid_lock);
1711 if (new_stat->nid_proc != NULL)
1712 lprocfs_remove(&new_stat->nid_proc);
1713 lustre_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
1714 OBD_FREE_PTR(new_ns_uuid);
1717 OBD_FREE_PTR(new_stat);
1721 int lprocfs_exp_cleanup(struct obd_export *exp)
1723 struct nid_stat *stat = exp->exp_nid_stats;
1724 struct nid_stat_uuid *cursor, *tmp;
1727 if(!stat || !exp->exp_obd)
1730 spin_lock(&exp->exp_obd->obd_nid_lock);
1731 list_for_each_entry_safe(cursor, tmp,
1732 &stat->nid_uuid_list,
1734 if (cursor && obd_uuid_equals(&cursor->ns_uuid,
1735 &exp->exp_client_uuid)) {
1737 list_del(&cursor->ns_uuid_list);
1738 OBD_FREE_PTR(cursor);
1739 --stat->nid_exp_ref_count;
1740 CDEBUG(D_INFO, "Put stat %p - %d\n", stat,
1741 stat->nid_exp_ref_count);
1745 spin_unlock(&exp->exp_obd->obd_nid_lock);
1747 CERROR("obd_export's client uuid %s are not found in its "
1748 "nid_stats list\n", exp->exp_client_uuid.uuid);
1750 exp->exp_nid_stats = NULL;
1751 lprocfs_free_md_stats(exp->exp_obd);
1756 int lprocfs_write_helper(const char *buffer, unsigned long count,
1759 return lprocfs_write_frac_helper(buffer, count, val, 1);
1762 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1765 char kernbuf[20], *end, *pbuf;
1767 if (count > (sizeof(kernbuf) - 1))
1770 if (copy_from_user(kernbuf, buffer, count))
1773 kernbuf[count] = '\0';
1780 *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1784 if (end != NULL && *end == '.') {
1785 int temp_val, pow = 1;
1789 if (strlen(pbuf) > 5)
1790 pbuf[5] = '\0'; /*only allow 5bits fractional*/
1792 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1795 for (i = 0; i < (end - pbuf); i++)
1798 *val += temp_val / pow;
1804 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
1807 long decimal_val, frac_val;
1813 decimal_val = val / mult;
1814 prtn = snprintf(buffer, count, "%ld", decimal_val);
1815 frac_val = val % mult;
1817 if (prtn < (count - 4) && frac_val > 0) {
1819 int i, temp_mult = 1, frac_bits = 0;
1821 temp_frac = frac_val * 10;
1822 buffer[prtn++] = '.';
1823 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
1824 /* only reserved 2 bits fraction */
1825 buffer[prtn++] ='0';
1830 * Need to think these cases :
1831 * 1. #echo x.00 > /proc/xxx output result : x
1832 * 2. #echo x.0x > /proc/xxx output result : x.0x
1833 * 3. #echo x.x0 > /proc/xxx output result : x.x
1834 * 4. #echo x.xx > /proc/xxx output result : x.xx
1835 * Only reserved 2 bits fraction.
1837 for (i = 0; i < (5 - prtn); i++)
1840 frac_bits = min((int)count - prtn, 3 - frac_bits);
1841 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
1842 frac_val * temp_mult / mult);
1845 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1847 if (buffer[prtn] == '.') {
1854 buffer[prtn++] ='\n';
1858 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1860 return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1863 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1864 __u64 *val, int mult)
1866 char kernbuf[22], *end, *pbuf;
1867 __u64 whole, frac = 0, units;
1868 unsigned frac_d = 1;
1870 if (count > (sizeof(kernbuf) - 1))
1873 if (copy_from_user(kernbuf, buffer, count))
1876 kernbuf[count] = '\0';
1883 whole = simple_strtoull(pbuf, &end, 10);
1887 if (end != NULL && *end == '.') {
1891 /* need to limit frac_d to a __u32 */
1892 if (strlen(pbuf) > 10)
1895 frac = simple_strtoull(pbuf, &end, 10);
1896 /* count decimal places */
1897 for (i = 0; i < (end - pbuf); i++)
1914 /* Specified units override the multiplier */
1916 mult = mult < 0 ? -units : units;
1919 do_div(frac, frac_d);
1920 *val = whole * mult + frac;
1924 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, char *name, mode_t mode,
1925 struct file_operations *seq_fops, void *data)
1927 struct proc_dir_entry *entry;
1930 entry = create_proc_entry(name, mode, parent);
1933 entry->proc_fops = seq_fops;
1938 EXPORT_SYMBOL(lprocfs_seq_create);
1940 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1942 struct file_operations *seq_fops,
1945 return (lprocfs_seq_create(dev->obd_proc_entry, name,
1946 mode, seq_fops, data));
1948 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1950 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1952 if (value >= OBD_HIST_MAX)
1953 value = OBD_HIST_MAX - 1;
1955 spin_lock(&oh->oh_lock);
1956 oh->oh_buckets[value]++;
1957 spin_unlock(&oh->oh_lock);
1959 EXPORT_SYMBOL(lprocfs_oh_tally);
1961 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1965 for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1968 lprocfs_oh_tally(oh, val);
1970 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1972 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1974 unsigned long ret = 0;
1977 for (i = 0; i < OBD_HIST_MAX; i++)
1978 ret += oh->oh_buckets[i];
1981 EXPORT_SYMBOL(lprocfs_oh_sum);
1983 void lprocfs_oh_clear(struct obd_histogram *oh)
1985 spin_lock(&oh->oh_lock);
1986 memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1987 spin_unlock(&oh->oh_lock);
1989 EXPORT_SYMBOL(lprocfs_oh_clear);
1991 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
1992 int count, int *eof, void *data)
1994 struct obd_device *obd = data;
2000 c += lustre_hash_debug_header(page, count);
2001 c += lustre_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2002 c += lustre_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2003 c += lustre_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2007 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2009 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2010 int count, int *eof, void *data)
2012 struct obd_device *obd = data;
2015 LASSERT(obd != NULL);
2016 LASSERT(count >= 0);
2018 /* Set start of user data returned to
2019 page + off since the user may have
2020 requested to read much smaller than
2021 what we need to read */
2022 *start = page + off;
2024 /* We know we are allocated a page here.
2025 Also we know that this function will
2026 not need to write more than a page
2027 so we can truncate at CFS_PAGE_SIZE. */
2028 size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
2030 /* Initialize the page */
2031 memset(page, 0, size);
2033 if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2035 if (obd->obd_max_recoverable_clients == 0) {
2036 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2042 /* sampled unlocked, but really... */
2043 if (obd->obd_recovering == 0) {
2044 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2046 if (lprocfs_obd_snprintf(&page, size, &len,
2047 "recovery_start: %lu\n",
2048 obd->obd_recovery_start) <= 0)
2050 if (lprocfs_obd_snprintf(&page, size, &len,
2051 "recovery_duration: %lu\n",
2052 obd->obd_recovery_end -
2053 obd->obd_recovery_start) <= 0)
2055 /* Number of clients that have completed recovery */
2056 if (lprocfs_obd_snprintf(&page, size, &len,
2057 "completed_clients: %d/%d\n",
2058 obd->obd_max_recoverable_clients -
2059 obd->obd_recoverable_clients,
2060 obd->obd_max_recoverable_clients) <= 0)
2062 if (lprocfs_obd_snprintf(&page, size, &len,
2063 "replayed_requests: %d\n",
2064 obd->obd_replayed_requests) <= 0)
2066 if (lprocfs_obd_snprintf(&page, size, &len,
2067 "last_transno: "LPD64"\n",
2068 obd->obd_next_recovery_transno - 1)<=0)
2073 if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2075 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2076 obd->obd_recovery_start) <= 0)
2078 if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2079 cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
2080 obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
2082 if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2083 obd->obd_connected_clients,
2084 obd->obd_max_recoverable_clients) <= 0)
2086 /* Number of clients that have completed recovery */
2087 if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d/%d\n",
2088 obd->obd_max_recoverable_clients -
2089 obd->obd_recoverable_clients,
2090 obd->obd_max_recoverable_clients) <= 0)
2092 if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d/??\n",
2093 obd->obd_replayed_requests) <= 0)
2095 if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2096 obd->obd_requests_queued_for_recovery) <= 0)
2099 if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2100 obd->obd_next_recovery_transno) <= 0)
2106 return min(count, len - (int)off);
2108 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2110 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
2111 int count, int *eof, void *data)
2113 struct obd_device *obd = data;
2114 LASSERT(obd != NULL);
2116 return snprintf(page, count, "%lu\n", obd->obd_recovery_max_time);
2118 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
2120 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
2121 unsigned long count, void *data)
2123 struct obd_device *obd = data;
2125 LASSERT(obd != NULL);
2127 rc = lprocfs_write_helper(buffer, count, &val);
2131 obd->obd_recovery_max_time = val;
2134 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
2137 /**** Changelogs *****/
2138 #define D_CHANGELOG 0
2140 DECLARE_CHANGELOG_NAMES;
2142 /* How many records per seq_show. Too small, we spawn llog_process threads
2143 too often; too large, we run out of buffer space */
2144 #define CHANGELOG_CHUNK_SIZE 100
2146 static int changelog_show_cb(struct llog_handle *llh, struct llog_rec_hdr *hdr,
2149 struct seq_file *seq = (struct seq_file *)data;
2150 struct changelog_seq_iter *csi = seq->private;
2151 struct llog_changelog_rec *rec = (struct llog_changelog_rec *)hdr;
2155 if ((rec->cr_hdr.lrh_type != CHANGELOG_REC) ||
2156 (rec->cr_type >= CL_LAST)) {
2157 CERROR("Not a changelog rec %d/%d\n", rec->cr_hdr.lrh_type,
2162 CDEBUG(D_CHANGELOG, "rec="LPU64" start="LPU64" cat=%d:%d start=%d:%d\n",
2163 rec->cr_index, csi->csi_startrec,
2164 llh->lgh_hdr->llh_cat_idx, llh->lgh_cur_idx,
2165 csi->csi_startcat, csi->csi_startidx);
2167 if (rec->cr_index < csi->csi_startrec)
2168 /* Skip entries earlier than what we are interested in */
2170 if (rec->cr_index == csi->csi_startrec) {
2171 /* Remember where we started, since seq_read will re-read
2172 * the data when it reallocs space. Sigh, if only there was
2173 * a way to tell seq_file how big the buf should be in the
2176 csi->csi_startcat = llh->lgh_hdr->llh_cat_idx;
2177 csi->csi_startidx = rec->cr_hdr.lrh_index - 1;
2179 if (csi->csi_wrote > CHANGELOG_CHUNK_SIZE) {
2180 /* Stop at some point with a reasonable seq_file buffer size.
2181 * Start from here the next time.
2183 csi->csi_endrec = rec->cr_index - 1;
2184 csi->csi_startcat = llh->lgh_hdr->llh_cat_idx;
2185 csi->csi_startidx = rec->cr_hdr.lrh_index - 1;
2187 RETURN(LLOG_PROC_BREAK);
2190 rc = seq_printf(seq, LPU64" %02d%-5s "LPU64" 0x%x t="DFID,
2191 rec->cr_index, rec->cr_type,
2192 changelog_str[rec->cr_type], rec->cr_time,
2193 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
2195 if (rec->cr_namelen)
2196 /* namespace rec includes parent and filename */
2197 rc += seq_printf(seq, " p="DFID" %.*s\n", PFID(&rec->cr_pfid),
2198 rec->cr_namelen, rec->cr_name);
2200 rc += seq_puts(seq, "\n");
2203 /* Ran out of room in the seq buffer. seq_read will dump
2204 * the whole buffer and re-seq_start with a larger one;
2205 * no point in continuing the llog_process */
2206 CDEBUG(D_CHANGELOG, "rec="LPU64" overflow "LPU64"<-"LPU64"\n",
2207 rec->cr_index, csi->csi_startrec, csi->csi_endrec);
2208 csi->csi_endrec = csi->csi_startrec - 1;
2210 RETURN(LLOG_PROC_BREAK);
2214 csi->csi_endrec = rec->cr_index;
2219 static int changelog_seq_show(struct seq_file *seq, void *v)
2221 struct changelog_seq_iter *csi = seq->private;
2225 if (csi->csi_fill) {
2226 /* seq_read wants more data to fill his buffer. But we already
2227 filled the buf as much as we cared to; force seq_read to
2228 accept that by padding with 0's */
2229 while (seq_putc(seq, 0) == 0);
2233 /* Since we have to restart the llog_cat_process for each chunk of the
2234 seq_ functions, start from where we left off. */
2235 rc = llog_cat_process(csi->csi_llh, changelog_show_cb, seq,
2236 csi->csi_startcat, csi->csi_startidx);
2238 CDEBUG(D_CHANGELOG,"seq_show "LPU64"-"LPU64" cat=%d:%d wrote=%d rc=%d\n",
2239 csi->csi_startrec, csi->csi_endrec, csi->csi_startcat,
2240 csi->csi_startidx, csi->csi_wrote, rc);
2244 if (rc == LLOG_PROC_BREAK)
2245 /* more records left, but seq_show must return 0 */
2250 static void *changelog_seq_start(struct seq_file *seq, loff_t *pos)
2252 struct changelog_seq_iter *csi = seq->private;
2255 CDEBUG(D_CHANGELOG, "start "LPU64"-"LPU64" pos="LPU64"\n",
2256 csi->csi_startrec, csi->csi_endrec, *pos);
2261 /* no more records, seq_read should return 0 if buffer
2265 if (*pos > csi->csi_pos) {
2266 /* The seq_read implementation sucks. It may call start
2267 multiple times, using pos to indicate advances, if any,
2268 by arbitrarily increasing it by 1. So ignore the actual
2269 value of pos, and just register any increase as
2270 "seq_read wants the next values". */
2271 csi->csi_startrec = csi->csi_endrec + 1;
2272 csi->csi_pos = *pos;
2274 /* else use old startrec/startidx */
2279 static void changelog_seq_stop(struct seq_file *seq, void *v)
2281 struct changelog_seq_iter *csi = seq->private;
2283 CDEBUG(D_CHANGELOG, "stop "LPU64"-"LPU64"\n",
2284 csi->csi_startrec, csi->csi_endrec);
2287 static void *changelog_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2289 struct changelog_seq_iter *csi = seq->private;
2291 CDEBUG(D_CHANGELOG, "next "LPU64"-"LPU64" pos="LPU64"\n",
2292 csi->csi_startrec, csi->csi_endrec, *pos);
2299 static struct seq_operations changelog_sops = {
2300 .start = changelog_seq_start,
2301 .stop = changelog_seq_stop,
2302 .next = changelog_seq_next,
2303 .show = changelog_seq_show,
2306 int changelog_seq_open(struct inode *inode, struct file *file,
2307 struct changelog_seq_iter **csih)
2309 struct changelog_seq_iter *csi;
2310 struct proc_dir_entry *dp = PDE(inode);
2311 struct seq_file *seq;
2314 LPROCFS_ENTRY_AND_CHECK(dp);
2316 rc = seq_open(file, &changelog_sops);
2324 lprocfs_seq_release(inode, file);
2328 csi->csi_dev = dp->data;
2329 seq = file->private_data;
2335 EXPORT_SYMBOL(changelog_seq_open);
2337 int changelog_seq_release(struct inode *inode, struct file *file)
2339 struct seq_file *seq = file->private_data;
2340 struct changelog_seq_iter *csi = seq->private;
2345 return lprocfs_seq_release(inode, file);
2347 EXPORT_SYMBOL(changelog_seq_release);
2349 #ifndef SEEK_CUR /* SLES10 needs this */
2354 loff_t changelog_seq_lseek(struct file *file, loff_t offset, int origin)
2356 struct seq_file *seq = (struct seq_file *)file->private_data;
2357 struct changelog_seq_iter *csi = seq->private;
2359 CDEBUG(D_CHANGELOG,"seek "LPU64"-"LPU64" off="LPU64":%d fpos="LPU64"\n",
2360 csi->csi_startrec, csi->csi_endrec, offset, origin, file->f_pos);
2366 offset += csi->csi_endrec;
2369 /* we don't know the last rec */
2380 csi->csi_startrec = offset;
2381 csi->csi_endrec = offset ? offset - 1 : 0;
2383 /* drop whatever is left in sucky seq_read's buffer */
2388 file->f_pos = csi->csi_startrec;
2389 return csi->csi_startrec;
2391 EXPORT_SYMBOL(changelog_seq_lseek);
2393 EXPORT_SYMBOL(lprocfs_register);
2394 EXPORT_SYMBOL(lprocfs_srch);
2395 EXPORT_SYMBOL(lprocfs_remove);
2396 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
2397 EXPORT_SYMBOL(lprocfs_add_vars);
2398 EXPORT_SYMBOL(lprocfs_obd_setup);
2399 EXPORT_SYMBOL(lprocfs_obd_cleanup);
2400 EXPORT_SYMBOL(lprocfs_add_simple);
2401 EXPORT_SYMBOL(lprocfs_add_symlink);
2402 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
2403 EXPORT_SYMBOL(lprocfs_alloc_stats);
2404 EXPORT_SYMBOL(lprocfs_free_stats);
2405 EXPORT_SYMBOL(lprocfs_clear_stats);
2406 EXPORT_SYMBOL(lprocfs_register_stats);
2407 EXPORT_SYMBOL(lprocfs_init_ops_stats);
2408 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
2409 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
2410 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
2411 EXPORT_SYMBOL(lprocfs_free_obd_stats);
2412 EXPORT_SYMBOL(lprocfs_exp_setup);
2413 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2415 EXPORT_SYMBOL(lprocfs_rd_u64);
2416 EXPORT_SYMBOL(lprocfs_rd_atomic);
2417 EXPORT_SYMBOL(lprocfs_wr_atomic);
2418 EXPORT_SYMBOL(lprocfs_rd_uint);
2419 EXPORT_SYMBOL(lprocfs_wr_uint);
2420 EXPORT_SYMBOL(lprocfs_rd_uuid);
2421 EXPORT_SYMBOL(lprocfs_rd_name);
2422 EXPORT_SYMBOL(lprocfs_rd_fstype);
2423 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
2424 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
2425 EXPORT_SYMBOL(lprocfs_rd_num_exports);
2426 EXPORT_SYMBOL(lprocfs_rd_numrefs);
2427 EXPORT_SYMBOL(lprocfs_at_hist_helper);
2428 EXPORT_SYMBOL(lprocfs_rd_import);
2429 EXPORT_SYMBOL(lprocfs_rd_timeouts);
2430 EXPORT_SYMBOL(lprocfs_rd_blksize);
2431 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
2432 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
2433 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
2434 EXPORT_SYMBOL(lprocfs_rd_filestotal);
2435 EXPORT_SYMBOL(lprocfs_rd_filesfree);
2437 EXPORT_SYMBOL(lprocfs_write_helper);
2438 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2439 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2440 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2441 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);