4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
23 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2013, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
32 * lustre/obdclass/lprocfs_status_server.c
35 #define DEBUG_SUBSYSTEM S_CLASS
38 #include <liblustre.h>
41 #include <obd_class.h>
42 #include <lprocfs_status.h>
43 #include <lustre/lustre_idl.h>
47 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
49 struct obd_device *obd = PDE_DATA(f->f_dentry->d_inode);
51 atomic_inc(&obd->obd_evict_inprogress);
55 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
57 struct obd_device *obd = PDE_DATA(f->f_dentry->d_inode);
59 atomic_dec(&obd->obd_evict_inprogress);
60 wake_up(&obd->obd_evict_inprogress_waitq);
65 #define BUFLEN (UUID_MAX + 5)
68 lprocfs_evict_client_seq_write(struct file *file, const char *buffer,
69 size_t count, loff_t *off)
71 struct seq_file *m = file->private_data;
72 struct obd_device *obd = m->private;
75 OBD_ALLOC(kbuf, BUFLEN);
80 * OBD_ALLOC() will zero kbuf, but we only copy BUFLEN - 1
81 * bytes into kbuf, to ensure that the string is NUL-terminated.
82 * UUID_MAX should include a trailing NUL already.
84 if (copy_from_user(kbuf, buffer,
85 min_t(unsigned long, BUFLEN - 1, count))) {
89 tmpbuf = cfs_firststr(kbuf, min_t(unsigned long, BUFLEN - 1, count));
90 class_incref(obd, __func__, current);
92 if (strncmp(tmpbuf, "nid:", 4) == 0)
93 obd_export_evict_by_nid(obd, tmpbuf + 4);
94 else if (strncmp(tmpbuf, "uuid:", 5) == 0)
95 obd_export_evict_by_uuid(obd, tmpbuf + 5);
97 obd_export_evict_by_uuid(obd, tmpbuf);
99 class_decref(obd, __func__, current);
102 OBD_FREE(kbuf, BUFLEN);
105 EXPORT_SYMBOL(lprocfs_evict_client_seq_write);
107 #ifndef HAVE_ONLY_PROCFS_SEQ
108 int lprocfs_wr_evict_client(struct file *file, const char __user *buffer,
109 unsigned long count, void *data)
111 struct obd_device *obd = data;
115 OBD_ALLOC(kbuf, BUFLEN);
120 * OBD_ALLOC() will zero kbuf, but we only copy BUFLEN - 1
121 * bytes into kbuf, to ensure that the string is NUL-terminated.
122 * UUID_MAX should include a trailing NUL already.
124 if (copy_from_user(kbuf, buffer,
125 min_t(unsigned long, BUFLEN - 1, count))) {
129 tmpbuf = cfs_firststr(kbuf, min_t(unsigned long, BUFLEN - 1, count));
130 class_incref(obd, __func__, current);
132 if (strncmp(tmpbuf, "nid:", 4) == 0)
133 obd_export_evict_by_nid(obd, tmpbuf + 4);
134 else if (strncmp(tmpbuf, "uuid:", 5) == 0)
135 obd_export_evict_by_uuid(obd, tmpbuf + 5);
137 obd_export_evict_by_uuid(obd, tmpbuf);
139 class_decref(obd, __func__, current);
141 OBD_FREE(kbuf, BUFLEN);
144 EXPORT_SYMBOL(lprocfs_wr_evict_client);
146 const struct file_operations lprocfs_evict_client_fops = {
147 .owner = THIS_MODULE,
148 .read = lprocfs_fops_read,
149 .write = lprocfs_fops_write,
150 .open = lprocfs_evict_client_open,
151 .release = lprocfs_evict_client_release,
153 EXPORT_SYMBOL(lprocfs_evict_client_fops);
155 /* Function that emulates snprintf but also has the side effect of advancing
156 the page pointer for the next write into the buffer, incrementing the total
157 length written to the buffer, and decrementing the size left in the
159 static int lprocfs_obd_snprintf(char **page, int end, int *len,
160 const char *format, ...)
168 va_start(list, format);
169 n = vsnprintf(*page, end - *len, format, list);
172 *page += n; *len += n;
175 #endif /* HAVE_ONLY_PROCFS_SEQ */
179 int lprocfs_num_exports_seq_show(struct seq_file *m, void *data)
181 struct obd_device *obd = data;
183 LASSERT(obd != NULL);
184 return seq_printf(m, "%u\n", obd->obd_num_exports);
186 EXPORT_SYMBOL(lprocfs_num_exports_seq_show);
188 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
190 CDEBUG(D_CONFIG, "stat %p - data %p/%p\n", client_stat,
191 client_stat->nid_proc, client_stat->nid_stats);
193 LASSERTF(atomic_read(&client_stat->nid_exp_ref_count) == 0,
194 "nid %s:count %d\n", libcfs_nid2str(client_stat->nid),
195 atomic_read(&client_stat->nid_exp_ref_count));
197 if (client_stat->nid_proc)
198 lprocfs_remove(&client_stat->nid_proc);
200 if (client_stat->nid_stats)
201 lprocfs_free_stats(&client_stat->nid_stats);
203 if (client_stat->nid_ldlm_stats)
204 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
206 OBD_FREE_PTR(client_stat);
210 void lprocfs_free_per_client_stats(struct obd_device *obd)
212 cfs_hash_t *hash = obd->obd_nid_stats_hash;
213 struct nid_stat *stat;
216 /* we need extra list - because hash_exit called to early */
217 /* not need locking because all clients is died */
218 while (!list_empty(&obd->obd_nid_stats)) {
219 stat = list_entry(obd->obd_nid_stats.next,
220 struct nid_stat, nid_list);
221 list_del_init(&stat->nid_list);
222 cfs_hash_del(hash, &stat->nid, &stat->nid_hash);
223 lprocfs_free_client_stats(stat);
227 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
229 int lprocfs_exp_nid_seq_show(struct seq_file *m, void *data)
231 struct obd_export *exp = m->private;
232 LASSERT(exp != NULL);
233 return seq_printf(m, "%s\n", obd_export_nid2str(exp));
236 int lprocfs_exp_print_uuid_seq(cfs_hash_t *hs, cfs_hash_bd_t *bd,
237 struct hlist_node *hnode, void *cb_data)
240 struct obd_export *exp = cfs_hash_object(hs, hnode);
241 struct seq_file *m = cb_data;
243 if (exp->exp_nid_stats)
244 seq_printf(m, "%s\n", obd_uuid2str(&exp->exp_client_uuid));
248 int lprocfs_exp_uuid_seq_show(struct seq_file *m, void *data)
250 struct nid_stat *stats = m->private;
251 struct obd_device *obd = stats->nid_obd;
253 cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
254 lprocfs_exp_print_uuid_seq, m);
257 LPROC_SEQ_FOPS_RO(lprocfs_exp_uuid);
259 int lprocfs_exp_print_hash_seq(cfs_hash_t *hs, cfs_hash_bd_t *bd,
260 struct hlist_node *hnode, void *cb_data)
263 struct seq_file *m = cb_data;
264 struct obd_export *exp = cfs_hash_object(hs, hnode);
266 if (exp->exp_lock_hash != NULL) {
267 cfs_hash_debug_header_seq(m);
268 cfs_hash_debug_str_seq(hs, m);
273 int lprocfs_exp_hash_seq_show(struct seq_file *m, void *data)
275 struct nid_stat *stats = m->private;
276 struct obd_device *obd = stats->nid_obd;
278 cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
279 lprocfs_exp_print_hash_seq, m);
282 LPROC_SEQ_FOPS_RO(lprocfs_exp_hash);
284 int lprocfs_nid_stats_clear_seq_show(struct seq_file *m, void *data)
286 return seq_printf(m, "%s\n", "Write into this file to clear all nid "
287 "stats and stale nid entries");
289 EXPORT_SYMBOL(lprocfs_nid_stats_clear_seq_show);
291 static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
293 struct nid_stat *stat = obj;
296 CDEBUG(D_INFO, "refcnt %d\n", atomic_read(&stat->nid_exp_ref_count));
297 if (atomic_read(&stat->nid_exp_ref_count) == 1) {
298 /* object has only hash references. */
299 spin_lock(&stat->nid_obd->obd_nid_lock);
300 list_move(&stat->nid_list, data);
301 spin_unlock(&stat->nid_obd->obd_nid_lock);
304 /* we has reference to object - only clear data*/
306 lprocfs_clear_stats(stat->nid_stats);
312 lprocfs_nid_stats_clear_seq_write(struct file *file, const char *buffer,
313 size_t count, loff_t *off)
315 struct list_head free_list = LIST_HEAD_INIT(free_list);
316 struct seq_file *m = file->private_data;
317 struct obd_device *obd = m->private;
318 struct nid_stat *client_stat;
320 cfs_hash_cond_del(obd->obd_nid_stats_hash,
321 lprocfs_nid_stats_clear_write_cb, &free_list);
323 while (!list_empty(&free_list)) {
324 client_stat = list_entry(free_list.next, struct nid_stat,
326 list_del_init(&client_stat->nid_list);
327 lprocfs_free_client_stats(client_stat);
331 EXPORT_SYMBOL(lprocfs_nid_stats_clear_seq_write);
333 #ifndef HAVE_ONLY_PROCFS_SEQ
334 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
335 int *eof, void *data)
337 struct obd_device *obd = data;
339 LASSERT(obd != NULL);
341 return snprintf(page, count, "%u\n", obd->obd_num_exports);
343 EXPORT_SYMBOL(lprocfs_rd_num_exports);
345 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
346 int *eof, void *data)
348 struct obd_export *exp = data;
349 LASSERT(exp != NULL);
351 return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
354 struct exp_uuid_cb_data {
362 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
363 int count, int *eof, int *len)
365 cb_data->page = page;
366 cb_data->count = count;
371 int lprocfs_exp_print_uuid(cfs_hash_t *hs, cfs_hash_bd_t *bd,
372 struct hlist_node *hnode, void *cb_data)
375 struct obd_export *exp = cfs_hash_object(hs, hnode);
376 struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
378 if (exp->exp_nid_stats)
379 *data->len += snprintf((data->page + *data->len),
381 obd_uuid2str(&exp->exp_client_uuid));
385 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
386 int *eof, void *data)
388 struct nid_stat *stats = (struct nid_stat *)data;
389 struct exp_uuid_cb_data cb_data;
390 struct obd_device *obd = stats->nid_obd;
395 lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
396 cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
397 lprocfs_exp_print_uuid, &cb_data);
401 int lprocfs_exp_print_hash(cfs_hash_t *hs, cfs_hash_bd_t *bd,
402 struct hlist_node *hnode, void *cb_data)
405 struct exp_uuid_cb_data *data = cb_data;
406 struct obd_export *exp = cfs_hash_object(hs, hnode);
408 if (exp->exp_lock_hash != NULL) {
410 *data->len += cfs_hash_debug_header(data->page,
413 *data->len += cfs_hash_debug_str(hs, data->page + *data->len,
419 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
420 int *eof, void *data)
422 struct nid_stat *stats = (struct nid_stat *)data;
423 struct exp_uuid_cb_data cb_data;
424 struct obd_device *obd = stats->nid_obd;
429 lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
431 cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
432 lprocfs_exp_print_hash, &cb_data);
436 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
437 int count, int *eof, void *data)
440 return snprintf(page, count, "%s\n",
441 "Write into this file to clear all nid stats and "
442 "stale nid entries");
444 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
446 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
447 unsigned long count, void *data)
449 struct list_head free_list = LIST_HEAD_INIT(free_list);
450 struct obd_device *obd = (struct obd_device *)data;
451 struct nid_stat *client_stat;
453 cfs_hash_cond_del(obd->obd_nid_stats_hash,
454 lprocfs_nid_stats_clear_write_cb, &free_list);
456 while (!list_empty(&free_list)) {
457 client_stat = list_entry(free_list.next, struct nid_stat,
459 list_del_init(&client_stat->nid_list);
460 lprocfs_free_client_stats(client_stat);
465 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
468 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
470 struct nid_stat *new_stat, *old_stat;
471 struct obd_device *obd = NULL;
472 struct proc_dir_entry *entry;
479 if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
480 !exp->exp_obd->obd_nid_stats_hash)
483 /* not test against zero because eric say:
484 * You may only test nid against another nid, or LNET_NID_ANY.
485 * Anything else is nonsense.*/
486 if (!nid || *nid == LNET_NID_ANY)
489 spin_lock(&exp->exp_lock);
490 if (exp->exp_nid_stats != NULL) {
491 spin_unlock(&exp->exp_lock);
494 spin_unlock(&exp->exp_lock);
498 CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
500 OBD_ALLOC_PTR(new_stat);
501 if (new_stat == NULL)
504 new_stat->nid = *nid;
505 new_stat->nid_obd = exp->exp_obd;
506 /* we need set default refcount to 1 to balance obd_disconnect */
507 atomic_set(&new_stat->nid_exp_ref_count, 1);
509 old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
510 nid, &new_stat->nid_hash);
511 CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
512 old_stat, libcfs_nid2str(*nid),
513 atomic_read(&new_stat->nid_exp_ref_count));
515 /* Return -EALREADY here so that we know that the /proc
516 * entry already has been created */
517 if (old_stat != new_stat) {
518 spin_lock(&exp->exp_lock);
519 if (exp->exp_nid_stats) {
520 LASSERT(exp->exp_nid_stats == old_stat);
521 nidstat_putref(exp->exp_nid_stats);
523 exp->exp_nid_stats = old_stat;
524 spin_unlock(&exp->exp_lock);
525 GOTO(destroy_new, rc = -EALREADY);
527 /* not found - create */
528 OBD_ALLOC(buffer, LNET_NIDSTR_SIZE);
530 GOTO(destroy_new, rc = -ENOMEM);
532 memcpy(buffer, libcfs_nid2str(*nid), LNET_NIDSTR_SIZE);
533 #ifndef HAVE_ONLY_PROCFS_SEQ
534 new_stat->nid_proc = lprocfs_register(buffer,
535 obd->obd_proc_exports_entry,
538 new_stat->nid_proc = lprocfs_seq_register(buffer,
539 obd->obd_proc_exports_entry,
542 OBD_FREE(buffer, LNET_NIDSTR_SIZE);
544 if (IS_ERR(new_stat->nid_proc)) {
545 rc = PTR_ERR(new_stat->nid_proc);
546 new_stat->nid_proc = NULL;
547 CERROR("%s: cannot create proc entry for export %s: rc = %d\n",
548 obd->obd_name, libcfs_nid2str(*nid), rc);
549 GOTO(destroy_new_ns, rc);
552 #ifndef HAVE_ONLY_PROCFS_SEQ
553 entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
554 lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
556 entry = lprocfs_add_simple(new_stat->nid_proc, "uuid", new_stat,
557 &lprocfs_exp_uuid_fops);
560 CWARN("Error adding the NID stats file\n");
562 GOTO(destroy_new_ns, rc);
565 #ifndef HAVE_ONLY_PROCFS_SEQ
566 entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
567 lprocfs_exp_rd_hash, NULL, new_stat, NULL);
569 entry = lprocfs_add_simple(new_stat->nid_proc, "hash", new_stat,
570 &lprocfs_exp_hash_fops);
573 CWARN("Error adding the hash file\n");
575 GOTO(destroy_new_ns, rc);
578 spin_lock(&exp->exp_lock);
579 exp->exp_nid_stats = new_stat;
580 spin_unlock(&exp->exp_lock);
582 /* protect competitive add to list, not need locking on destroy */
583 spin_lock(&obd->obd_nid_lock);
584 list_add(&new_stat->nid_list, &obd->obd_nid_stats);
585 spin_unlock(&obd->obd_nid_lock);
590 if (new_stat->nid_proc != NULL)
591 lprocfs_remove(&new_stat->nid_proc);
592 cfs_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
595 nidstat_putref(new_stat);
596 OBD_FREE_PTR(new_stat);
599 EXPORT_SYMBOL(lprocfs_exp_setup);
601 int lprocfs_exp_cleanup(struct obd_export *exp)
603 struct nid_stat *stat = exp->exp_nid_stats;
605 if (!stat || !exp->exp_obd)
608 nidstat_putref(exp->exp_nid_stats);
609 exp->exp_nid_stats = NULL;
613 EXPORT_SYMBOL(lprocfs_exp_cleanup);
615 #define LPROCFS_OBD_OP_INIT(base, stats, op) \
617 unsigned int coffset = base + OBD_COUNTER_OFFSET(op); \
618 LASSERT(coffset < stats->ls_num); \
619 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
622 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
624 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
625 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
626 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
627 LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
628 LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
629 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
630 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
631 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
632 LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
633 LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
634 LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
635 LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
636 LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
637 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
638 LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
639 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
640 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
641 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
642 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
643 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
644 LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
645 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
646 LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
647 LPROCFS_OBD_OP_INIT(num_private_stats, stats, create_async);
648 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
649 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
650 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
651 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
652 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
653 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
654 LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
655 LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
656 LPROCFS_OBD_OP_INIT(num_private_stats, stats, find_cbdata);
657 LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
658 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
659 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
660 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
661 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
662 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
663 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
664 LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
665 LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
666 LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
667 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
668 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
669 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
670 LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
671 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
672 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
673 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
674 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
675 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
676 LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
678 CLASSERT(NUM_OBD_STATS == OBD_COUNTER_OFFSET(putref) + 1);
680 EXPORT_SYMBOL(lprocfs_init_ops_stats);
682 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
684 struct lprocfs_stats *stats;
685 unsigned int num_stats;
688 LASSERT(obd->obd_stats == NULL);
689 LASSERT(obd->obd_proc_entry != NULL);
690 LASSERT(obd->obd_cntr_base == 0);
692 num_stats = NUM_OBD_STATS + num_private_stats;
693 stats = lprocfs_alloc_stats(num_stats, 0);
697 lprocfs_init_ops_stats(num_private_stats, stats);
699 for (i = num_private_stats; i < num_stats; i++) {
700 /* If this LBUGs, it is likely that an obd
701 * operation was added to struct obd_ops in
702 * <obd.h>, and that the corresponding line item
703 * LPROCFS_OBD_OP_INIT(.., .., opname)
704 * is missing from the list above. */
705 LASSERTF(stats->ls_cnt_header[i].lc_name != NULL,
706 "Missing obd_stat initializer obd_op "
707 "operation at offset %d.\n", i - num_private_stats);
709 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
711 lprocfs_free_stats(&stats);
713 obd->obd_stats = stats;
714 obd->obd_cntr_base = num_private_stats;
718 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
720 void lprocfs_free_obd_stats(struct obd_device *obd)
723 lprocfs_free_stats(&obd->obd_stats);
725 EXPORT_SYMBOL(lprocfs_free_obd_stats);
727 int lprocfs_hash_seq_show(struct seq_file *m, void *data)
729 struct obd_device *obd = m->private;
735 c += cfs_hash_debug_header_seq(m);
736 c += cfs_hash_debug_str_seq(obd->obd_uuid_hash, m);
737 c += cfs_hash_debug_str_seq(obd->obd_nid_hash, m);
738 c += cfs_hash_debug_str_seq(obd->obd_nid_stats_hash, m);
741 EXPORT_SYMBOL(lprocfs_hash_seq_show);
743 int lprocfs_recovery_status_seq_show(struct seq_file *m, void *data)
745 struct obd_device *obd = m->private;
747 LASSERT(obd != NULL);
749 seq_printf(m, "status: ");
750 if (obd->obd_max_recoverable_clients == 0) {
751 seq_printf(m, "INACTIVE\n");
755 /* sampled unlocked, but really... */
756 if (obd->obd_recovering == 0) {
757 seq_printf(m, "COMPLETE\n");
758 seq_printf(m, "recovery_start: %lu\n", obd->obd_recovery_start);
759 seq_printf(m, "recovery_duration: %lu\n",
760 obd->obd_recovery_end - obd->obd_recovery_start);
761 /* Number of clients that have completed recovery */
762 seq_printf(m, "completed_clients: %d/%d\n",
763 obd->obd_max_recoverable_clients -
764 obd->obd_stale_clients,
765 obd->obd_max_recoverable_clients);
766 seq_printf(m, "replayed_requests: %d\n",
767 obd->obd_replayed_requests);
768 seq_printf(m, "last_transno: "LPD64"\n",
769 obd->obd_next_recovery_transno - 1);
770 seq_printf(m, "VBR: %s\n", obd->obd_version_recov ?
771 "ENABLED" : "DISABLED");
772 seq_printf(m, "IR: %s\n", obd->obd_no_ir ?
773 "DISABLED" : "ENABLED");
777 seq_printf(m, "RECOVERING\n");
778 seq_printf(m, "recovery_start: %lu\n", obd->obd_recovery_start);
779 seq_printf(m, "time_remaining: %lu\n",
780 cfs_time_current_sec() >=
781 obd->obd_recovery_start +
782 obd->obd_recovery_timeout ? 0 :
783 obd->obd_recovery_start +
784 obd->obd_recovery_timeout -
785 cfs_time_current_sec());
786 seq_printf(m, "connected_clients: %d/%d\n",
787 atomic_read(&obd->obd_connected_clients),
788 obd->obd_max_recoverable_clients);
789 /* Number of clients that have completed recovery */
790 seq_printf(m, "req_replay_clients: %d\n",
791 atomic_read(&obd->obd_req_replay_clients));
792 seq_printf(m, "lock_repay_clients: %d\n",
793 atomic_read(&obd->obd_lock_replay_clients));
794 seq_printf(m, "completed_clients: %d\n",
795 atomic_read(&obd->obd_connected_clients) -
796 atomic_read(&obd->obd_lock_replay_clients));
797 seq_printf(m, "evicted_clients: %d\n", obd->obd_stale_clients);
798 seq_printf(m, "replayed_requests: %d\n", obd->obd_replayed_requests);
799 seq_printf(m, "queued_requests: %d\n",
800 obd->obd_requests_queued_for_recovery);
801 seq_printf(m, "next_transno: "LPD64"\n",
802 obd->obd_next_recovery_transno);
806 EXPORT_SYMBOL(lprocfs_recovery_status_seq_show);
808 int lprocfs_ir_factor_seq_show(struct seq_file *m, void *data)
810 struct obd_device *obd = m->private;
812 LASSERT(obd != NULL);
813 return seq_printf(m, "%d\n", obd->obd_recovery_ir_factor);
815 EXPORT_SYMBOL(lprocfs_ir_factor_seq_show);
818 lprocfs_ir_factor_seq_write(struct file *file, const char *buffer,
819 size_t count, loff_t *off)
821 struct seq_file *m = file->private_data;
822 struct obd_device *obd = m->private;
825 LASSERT(obd != NULL);
826 rc = lprocfs_write_helper(buffer, count, &val);
830 if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
833 obd->obd_recovery_ir_factor = val;
836 EXPORT_SYMBOL(lprocfs_ir_factor_seq_write);
838 int lprocfs_recovery_time_soft_seq_show(struct seq_file *m, void *data)
840 struct obd_device *obd = m->private;
842 LASSERT(obd != NULL);
843 return seq_printf(m, "%d\n", obd->obd_recovery_timeout);
845 EXPORT_SYMBOL(lprocfs_recovery_time_soft_seq_show);
848 lprocfs_recovery_time_soft_seq_write(struct file *file, const char *buffer,
849 size_t count, loff_t *off)
851 struct seq_file *m = file->private_data;
852 struct obd_device *obd = m->private;
855 LASSERT(obd != NULL);
856 rc = lprocfs_write_helper(buffer, count, &val);
860 obd->obd_recovery_timeout = val;
863 EXPORT_SYMBOL(lprocfs_recovery_time_soft_seq_write);
865 int lprocfs_recovery_time_hard_seq_show(struct seq_file *m, void *data)
867 struct obd_device *obd = m->private;
869 LASSERT(obd != NULL);
870 return seq_printf(m, "%u\n", obd->obd_recovery_time_hard);
872 EXPORT_SYMBOL(lprocfs_recovery_time_hard_seq_show);
875 lprocfs_recovery_time_hard_seq_write(struct file *file, const char *buffer,
876 size_t count, loff_t *off)
878 struct seq_file *m = file->private_data;
879 struct obd_device *obd = m->private;
882 LASSERT(obd != NULL);
883 rc = lprocfs_write_helper(buffer, count, &val);
887 obd->obd_recovery_time_hard = val;
890 EXPORT_SYMBOL(lprocfs_recovery_time_hard_seq_write);
892 int lprocfs_target_instance_seq_show(struct seq_file *m, void *data)
894 struct obd_device *obd = m->private;
895 struct obd_device_target *target = &obd->u.obt;
897 LASSERT(obd != NULL);
898 LASSERT(target->obt_magic == OBT_MAGIC);
899 return seq_printf(m, "%u\n", obd->u.obt.obt_instance);
901 EXPORT_SYMBOL(lprocfs_target_instance_seq_show);
903 #ifndef HAVE_ONLY_PROCFS_SEQ
904 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
905 int count, int *eof, void *data)
907 struct obd_device *obd = data;
913 c += cfs_hash_debug_header(page, count);
914 c += cfs_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
915 c += cfs_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
916 c += cfs_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
920 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
922 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
923 int count, int *eof, void *data)
925 struct obd_device *obd = data;
928 LASSERT(obd != NULL);
931 /* Set start of user data returned to
932 page + off since the user may have
933 requested to read much smaller than
934 what we need to read */
938 * We know we are allocated a page here.
939 * Also we know that this function will
940 * not need to write more than a page
941 * so we can truncate at PAGE_CACHE_SIZE.
943 size = min(count + (int)off + 1, (int)PAGE_CACHE_SIZE);
945 /* Initialize the page */
946 memset(page, 0, size);
948 if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
950 if (obd->obd_max_recoverable_clients == 0) {
951 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
957 /* sampled unlocked, but really... */
958 if (obd->obd_recovering == 0) {
959 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
961 if (lprocfs_obd_snprintf(&page, size, &len,
962 "recovery_start: %lu\n",
963 obd->obd_recovery_start) <= 0)
965 if (lprocfs_obd_snprintf(&page, size, &len,
966 "recovery_duration: %lu\n",
967 obd->obd_recovery_end -
968 obd->obd_recovery_start) <= 0)
970 /* Number of clients that have completed recovery */
971 if (lprocfs_obd_snprintf(&page, size, &len,
972 "completed_clients: %d/%d\n",
973 obd->obd_max_recoverable_clients -
974 obd->obd_stale_clients,
975 obd->obd_max_recoverable_clients) <= 0)
977 if (lprocfs_obd_snprintf(&page, size, &len,
978 "replayed_requests: %d\n",
979 obd->obd_replayed_requests) <= 0)
981 if (lprocfs_obd_snprintf(&page, size, &len,
982 "last_transno: "LPD64"\n",
983 obd->obd_next_recovery_transno - 1) <= 0)
985 if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
986 obd->obd_version_recov ?
987 "ENABLED" : "DISABLED") <= 0)
989 if (lprocfs_obd_snprintf(&page, size, &len, "IR: %s\n",
991 "DISABLED" : "ENABLED") <= 0)
996 if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
998 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
999 obd->obd_recovery_start) <= 0)
1001 if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
1002 cfs_time_current_sec() >=
1003 obd->obd_recovery_start +
1004 obd->obd_recovery_timeout ? 0 :
1005 obd->obd_recovery_start +
1006 obd->obd_recovery_timeout -
1007 cfs_time_current_sec()) <= 0)
1009 if (lprocfs_obd_snprintf(&page, size, &len,
1010 "connected_clients: %d/%d\n",
1011 atomic_read(&obd->obd_connected_clients),
1012 obd->obd_max_recoverable_clients) <= 0)
1014 /* Number of clients that have completed recovery */
1015 if (lprocfs_obd_snprintf(&page, size, &len, "req_replay_clients: %d\n",
1016 atomic_read(&obd->obd_req_replay_clients))
1019 if (lprocfs_obd_snprintf(&page, size, &len, "lock_repay_clients: %d\n",
1020 atomic_read(&obd->obd_lock_replay_clients))
1023 if (lprocfs_obd_snprintf(&page, size, &len, "completed_clients: %d\n",
1024 atomic_read(&obd->obd_connected_clients) -
1025 atomic_read(&obd->obd_lock_replay_clients))
1028 if (lprocfs_obd_snprintf(&page, size, &len, "evicted_clients: %d\n",
1029 obd->obd_stale_clients) <= 0)
1031 if (lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d\n",
1032 obd->obd_replayed_requests) <= 0)
1034 if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1035 obd->obd_requests_queued_for_recovery) <= 0)
1038 if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
1039 obd->obd_next_recovery_transno) <= 0)
1045 return min(count, len - (int)off);
1047 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1049 int lprocfs_obd_rd_ir_factor(char *page, char **start, off_t off,
1050 int count, int *eof, void *data)
1052 struct obd_device *obd = (struct obd_device *)data;
1053 LASSERT(obd != NULL);
1055 return snprintf(page, count, "%d\n",
1056 obd->obd_recovery_ir_factor);
1058 EXPORT_SYMBOL(lprocfs_obd_rd_ir_factor);
1060 int lprocfs_obd_wr_ir_factor(struct file *file, const char *buffer,
1061 unsigned long count, void *data)
1063 struct obd_device *obd = (struct obd_device *)data;
1065 LASSERT(obd != NULL);
1067 rc = lprocfs_write_helper(buffer, count, &val);
1071 if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
1074 obd->obd_recovery_ir_factor = val;
1077 EXPORT_SYMBOL(lprocfs_obd_wr_ir_factor);
1079 int lprocfs_obd_rd_recovery_time_soft(char *page, char **start, off_t off,
1080 int count, int *eof, void *data)
1082 struct obd_device *obd = (struct obd_device *)data;
1083 LASSERT(obd != NULL);
1085 return snprintf(page, count, "%d\n",
1086 obd->obd_recovery_timeout);
1088 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_soft);
1090 int lprocfs_obd_wr_recovery_time_soft(struct file *file, const char *buffer,
1091 unsigned long count, void *data)
1093 struct obd_device *obd = (struct obd_device *)data;
1095 LASSERT(obd != NULL);
1097 rc = lprocfs_write_helper(buffer, count, &val);
1101 obd->obd_recovery_timeout = val;
1104 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_soft);
1106 int lprocfs_obd_rd_recovery_time_hard(char *page, char **start, off_t off,
1107 int count, int *eof, void *data)
1109 struct obd_device *obd = data;
1110 LASSERT(obd != NULL);
1112 return snprintf(page, count, "%u\n", obd->obd_recovery_time_hard);
1114 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_hard);
1116 int lprocfs_obd_wr_recovery_time_hard(struct file *file, const char *buffer,
1117 unsigned long count, void *data)
1119 struct obd_device *obd = data;
1121 LASSERT(obd != NULL);
1123 rc = lprocfs_write_helper(buffer, count, &val);
1127 obd->obd_recovery_time_hard = val;
1130 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_hard);
1132 int lprocfs_target_rd_instance(char *page, char **start, off_t off,
1133 int count, int *eof, void *data)
1135 struct obd_device *obd = (struct obd_device *)data;
1136 struct obd_device_target *target = &obd->u.obt;
1138 LASSERT(obd != NULL);
1139 LASSERT(target->obt_magic == OBT_MAGIC);
1141 return snprintf(page, count, "%u\n", obd->u.obt.obt_instance);
1143 EXPORT_SYMBOL(lprocfs_target_rd_instance);
1144 #endif /* HAVE_ONLY_PROCFS_SEQ */