aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jbd2/journal.c
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2009-09-30 00:32:06 -0400
committerTheodore Ts'o <tytso@mit.edu>2009-09-30 00:32:06 -0400
commitbf6993276f74d46776f35c45ddef29b981b1d1c6 (patch)
tree5c9cb128fed29a83add1932b12443edaa6fd06cc /fs/jbd2/journal.c
parent296c355cd6443d89fa251885a8d78778fe111dc4 (diff)
jbd2: Use tracepoints for history file
The /proc/fs/jbd2/<dev>/history was maintained manually; by using tracepoints, we can get all of the existing functionality of the /proc file plus extra capabilities thanks to the ftrace infrastructure. We save memory as a bonus. Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/jbd2/journal.c')
-rw-r--r--fs/jbd2/journal.c187
1 files changed, 10 insertions, 177 deletions
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 977a8dafb76d..761af77491f5 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -676,153 +676,6 @@ struct jbd2_stats_proc_session {
676 int max; 676 int max;
677}; 677};
678 678
679static void *jbd2_history_skip_empty(struct jbd2_stats_proc_session *s,
680 struct transaction_stats_s *ts,
681 int first)
682{
683 if (ts == s->stats + s->max)
684 ts = s->stats;
685 if (!first && ts == s->stats + s->start)
686 return NULL;
687 while (ts->ts_type == 0) {
688 ts++;
689 if (ts == s->stats + s->max)
690 ts = s->stats;
691 if (ts == s->stats + s->start)
692 return NULL;
693 }
694 return ts;
695
696}
697
698static void *jbd2_seq_history_start(struct seq_file *seq, loff_t *pos)
699{
700 struct jbd2_stats_proc_session *s = seq->private;
701 struct transaction_stats_s *ts;
702 int l = *pos;
703
704 if (l == 0)
705 return SEQ_START_TOKEN;
706 ts = jbd2_history_skip_empty(s, s->stats + s->start, 1);
707 if (!ts)
708 return NULL;
709 l--;
710 while (l) {
711 ts = jbd2_history_skip_empty(s, ++ts, 0);
712 if (!ts)
713 break;
714 l--;
715 }
716 return ts;
717}
718
719static void *jbd2_seq_history_next(struct seq_file *seq, void *v, loff_t *pos)
720{
721 struct jbd2_stats_proc_session *s = seq->private;
722 struct transaction_stats_s *ts = v;
723
724 ++*pos;
725 if (v == SEQ_START_TOKEN)
726 return jbd2_history_skip_empty(s, s->stats + s->start, 1);
727 else
728 return jbd2_history_skip_empty(s, ++ts, 0);
729}
730
731static int jbd2_seq_history_show(struct seq_file *seq, void *v)
732{
733 struct transaction_stats_s *ts = v;
734 if (v == SEQ_START_TOKEN) {
735 seq_printf(seq, "%-4s %-5s %-5s %-5s %-5s %-5s %-5s %-6s %-5s "
736 "%-5s %-5s %-5s %-5s %-5s\n", "R/C", "tid",
737 "wait", "run", "lock", "flush", "log", "hndls",
738 "block", "inlog", "ctime", "write", "drop",
739 "close");
740 return 0;
741 }
742 if (ts->ts_type == JBD2_STATS_RUN)
743 seq_printf(seq, "%-4s %-5lu %-5u %-5u %-5u %-5u %-5u "
744 "%-6lu %-5lu %-5lu\n", "R", ts->ts_tid,
745 jiffies_to_msecs(ts->u.run.rs_wait),
746 jiffies_to_msecs(ts->u.run.rs_running),
747 jiffies_to_msecs(ts->u.run.rs_locked),
748 jiffies_to_msecs(ts->u.run.rs_flushing),
749 jiffies_to_msecs(ts->u.run.rs_logging),
750 ts->u.run.rs_handle_count,
751 ts->u.run.rs_blocks,
752 ts->u.run.rs_blocks_logged);
753 else if (ts->ts_type == JBD2_STATS_CHECKPOINT)
754 seq_printf(seq, "%-4s %-5lu %48s %-5u %-5lu %-5lu %-5lu\n",
755 "C", ts->ts_tid, " ",
756 jiffies_to_msecs(ts->u.chp.cs_chp_time),
757 ts->u.chp.cs_written, ts->u.chp.cs_dropped,
758 ts->u.chp.cs_forced_to_close);
759 else
760 J_ASSERT(0);
761 return 0;
762}
763
764static void jbd2_seq_history_stop(struct seq_file *seq, void *v)
765{
766}
767
768static const struct seq_operations jbd2_seq_history_ops = {
769 .start = jbd2_seq_history_start,
770 .next = jbd2_seq_history_next,
771 .stop = jbd2_seq_history_stop,
772 .show = jbd2_seq_history_show,
773};
774
775static int jbd2_seq_history_open(struct inode *inode, struct file *file)
776{
777 journal_t *journal = PDE(inode)->data;
778 struct jbd2_stats_proc_session *s;
779 int rc, size;
780
781 s = kmalloc(sizeof(*s), GFP_KERNEL);
782 if (s == NULL)
783 return -ENOMEM;
784 size = sizeof(struct transaction_stats_s) * journal->j_history_max;
785 s->stats = kmalloc(size, GFP_KERNEL);
786 if (s->stats == NULL) {
787 kfree(s);
788 return -ENOMEM;
789 }
790 spin_lock(&journal->j_history_lock);
791 memcpy(s->stats, journal->j_history, size);
792 s->max = journal->j_history_max;
793 s->start = journal->j_history_cur % s->max;
794 spin_unlock(&journal->j_history_lock);
795
796 rc = seq_open(file, &jbd2_seq_history_ops);
797 if (rc == 0) {
798 struct seq_file *m = file->private_data;
799 m->private = s;
800 } else {
801 kfree(s->stats);
802 kfree(s);
803 }
804 return rc;
805
806}
807
808static int jbd2_seq_history_release(struct inode *inode, struct file *file)
809{
810 struct seq_file *seq = file->private_data;
811 struct jbd2_stats_proc_session *s = seq->private;
812
813 kfree(s->stats);
814 kfree(s);
815 return seq_release(inode, file);
816}
817
818static struct file_operations jbd2_seq_history_fops = {
819 .owner = THIS_MODULE,
820 .open = jbd2_seq_history_open,
821 .read = seq_read,
822 .llseek = seq_lseek,
823 .release = jbd2_seq_history_release,
824};
825
826static void *jbd2_seq_info_start(struct seq_file *seq, loff_t *pos) 679static void *jbd2_seq_info_start(struct seq_file *seq, loff_t *pos)
827{ 680{
828 return *pos ? NULL : SEQ_START_TOKEN; 681 return *pos ? NULL : SEQ_START_TOKEN;
@@ -839,29 +692,29 @@ static int jbd2_seq_info_show(struct seq_file *seq, void *v)
839 692
840 if (v != SEQ_START_TOKEN) 693 if (v != SEQ_START_TOKEN)
841 return 0; 694 return 0;
842 seq_printf(seq, "%lu transaction, each upto %u blocks\n", 695 seq_printf(seq, "%lu transaction, each up to %u blocks\n",
843 s->stats->ts_tid, 696 s->stats->ts_tid,
844 s->journal->j_max_transaction_buffers); 697 s->journal->j_max_transaction_buffers);
845 if (s->stats->ts_tid == 0) 698 if (s->stats->ts_tid == 0)
846 return 0; 699 return 0;
847 seq_printf(seq, "average: \n %ums waiting for transaction\n", 700 seq_printf(seq, "average: \n %ums waiting for transaction\n",
848 jiffies_to_msecs(s->stats->u.run.rs_wait / s->stats->ts_tid)); 701 jiffies_to_msecs(s->stats->run.rs_wait / s->stats->ts_tid));
849 seq_printf(seq, " %ums running transaction\n", 702 seq_printf(seq, " %ums running transaction\n",
850 jiffies_to_msecs(s->stats->u.run.rs_running / s->stats->ts_tid)); 703 jiffies_to_msecs(s->stats->run.rs_running / s->stats->ts_tid));
851 seq_printf(seq, " %ums transaction was being locked\n", 704 seq_printf(seq, " %ums transaction was being locked\n",
852 jiffies_to_msecs(s->stats->u.run.rs_locked / s->stats->ts_tid)); 705 jiffies_to_msecs(s->stats->run.rs_locked / s->stats->ts_tid));
853 seq_printf(seq, " %ums flushing data (in ordered mode)\n", 706 seq_printf(seq, " %ums flushing data (in ordered mode)\n",
854 jiffies_to_msecs(s->stats->u.run.rs_flushing / s->stats->ts_tid)); 707 jiffies_to_msecs(s->stats->run.rs_flushing / s->stats->ts_tid));
855 seq_printf(seq, " %ums logging transaction\n", 708 seq_printf(seq, " %ums logging transaction\n",
856 jiffies_to_msecs(s->stats->u.run.rs_logging / s->stats->ts_tid)); 709 jiffies_to_msecs(s->stats->run.rs_logging / s->stats->ts_tid));
857 seq_printf(seq, " %lluus average transaction commit time\n", 710 seq_printf(seq, " %lluus average transaction commit time\n",
858 div_u64(s->journal->j_average_commit_time, 1000)); 711 div_u64(s->journal->j_average_commit_time, 1000));
859 seq_printf(seq, " %lu handles per transaction\n", 712 seq_printf(seq, " %lu handles per transaction\n",
860 s->stats->u.run.rs_handle_count / s->stats->ts_tid); 713 s->stats->run.rs_handle_count / s->stats->ts_tid);
861 seq_printf(seq, " %lu blocks per transaction\n", 714 seq_printf(seq, " %lu blocks per transaction\n",
862 s->stats->u.run.rs_blocks / s->stats->ts_tid); 715 s->stats->run.rs_blocks / s->stats->ts_tid);
863 seq_printf(seq, " %lu logged blocks per transaction\n", 716 seq_printf(seq, " %lu logged blocks per transaction\n",
864 s->stats->u.run.rs_blocks_logged / s->stats->ts_tid); 717 s->stats->run.rs_blocks_logged / s->stats->ts_tid);
865 return 0; 718 return 0;
866} 719}
867 720
@@ -931,8 +784,6 @@ static void jbd2_stats_proc_init(journal_t *journal)
931{ 784{
932 journal->j_proc_entry = proc_mkdir(journal->j_devname, proc_jbd2_stats); 785 journal->j_proc_entry = proc_mkdir(journal->j_devname, proc_jbd2_stats);
933 if (journal->j_proc_entry) { 786 if (journal->j_proc_entry) {
934 proc_create_data("history", S_IRUGO, journal->j_proc_entry,
935 &jbd2_seq_history_fops, journal);
936 proc_create_data("info", S_IRUGO, journal->j_proc_entry, 787 proc_create_data("info", S_IRUGO, journal->j_proc_entry,
937 &jbd2_seq_info_fops, journal); 788 &jbd2_seq_info_fops, journal);
938 } 789 }
@@ -941,27 +792,9 @@ static void jbd2_stats_proc_init(journal_t *journal)
941static void jbd2_stats_proc_exit(journal_t *journal) 792static void jbd2_stats_proc_exit(journal_t *journal)
942{ 793{
943 remove_proc_entry("info", journal->j_proc_entry); 794 remove_proc_entry("info", journal->j_proc_entry);
944 remove_proc_entry("history", journal->j_proc_entry);
945 remove_proc_entry(journal->j_devname, proc_jbd2_stats); 795 remove_proc_entry(journal->j_devname, proc_jbd2_stats);
946} 796}
947 797
948static void journal_init_stats(journal_t *journal)
949{
950 int size;
951
952 if (!proc_jbd2_stats)
953 return;
954
955 journal->j_history_max = 100;
956 size = sizeof(struct transaction_stats_s) * journal->j_history_max;
957 journal->j_history = kzalloc(size, GFP_KERNEL);
958 if (!journal->j_history) {
959 journal->j_history_max = 0;
960 return;
961 }
962 spin_lock_init(&journal->j_history_lock);
963}
964
965/* 798/*
966 * Management for journal control blocks: functions to create and 799 * Management for journal control blocks: functions to create and
967 * destroy journal_t structures, and to initialise and read existing 800 * destroy journal_t structures, and to initialise and read existing
@@ -1006,7 +839,7 @@ static journal_t * journal_init_common (void)
1006 goto fail; 839 goto fail;
1007 } 840 }
1008 841
1009 journal_init_stats(journal); 842 spin_lock_init(&journal->j_history_lock);
1010 843
1011 return journal; 844 return journal;
1012fail: 845fail: