+++ /dev/null
-Index: linux-2.6.9/include/linux/jbd.h
-===================================================================
---- linux-2.6.9.orig/include/linux/jbd.h
-+++ linux-2.6.9/include/linux/jbd.h
-@@ -422,6 +422,16 @@ struct handle_s
- };
-
-
-+/*
-+ * Some stats for checkpoint phase
-+ */
-+struct transaction_chp_stats_s {
-+ unsigned long cs_chp_time;
-+ unsigned long cs_forced_to_close;
-+ unsigned long cs_written;
-+ unsigned long cs_dropped;
-+};
-+
- /* The transaction_t type is the guts of the journaling mechanism. It
- * tracks a compound transaction through its various states:
- *
-@@ -553,6 +563,21 @@ struct transaction_s
- spinlock_t t_handle_lock;
-
- /*
-+ * Longest time some handle had to wait for running transaction
-+ */
-+ unsigned long t_max_wait;
-+
-+ /*
-+ * When transaction started
-+ */
-+ unsigned long t_start;
-+
-+ /*
-+ * Checkpointing stats [j_checkpoint_sem]
-+ */
-+ struct transaction_chp_stats_s t_chp_stats;
-+
-+ /*
- * Number of outstanding updates running on this transaction
- * [t_handle_lock]
- */
-@@ -592,6 +617,57 @@ struct transaction_s
- #endif
- };
-
-+struct transaction_run_stats_s {
-+ unsigned long rs_wait;
-+ unsigned long rs_running;
-+ unsigned long rs_locked;
-+ unsigned long rs_flushing;
-+ unsigned long rs_logging;
-+
-+ unsigned long rs_handle_count;
-+ unsigned long rs_blocks;
-+ unsigned long rs_blocks_logged;
-+};
-+
-+struct transaction_stats_s
-+{
-+ int ts_type;
-+ unsigned long ts_tid;
-+ union {
-+ struct transaction_run_stats_s run;
-+ struct transaction_chp_stats_s chp;
-+ } u;
-+};
-+
-+#define JBD_STATS_RUN 1
-+#define JBD_STATS_CHECKPOINT 2
-+
-+#define ts_wait u.run.rs_wait
-+#define ts_running u.run.rs_running
-+#define ts_locked u.run.rs_locked
-+#define ts_flushing u.run.rs_flushing
-+#define ts_logging u.run.rs_logging
-+#define ts_handle_count u.run.rs_handle_count
-+#define ts_blocks u.run.rs_blocks
-+#define ts_blocks_logged u.run.rs_blocks_logged
-+
-+#define ts_chp_time u.chp.cs_chp_time
-+#define ts_forced_to_close u.chp.cs_forced_to_close
-+#define ts_written u.chp.cs_written
-+#define ts_dropped u.chp.cs_dropped
-+
-+#define CURRENT_MSECS (jiffies_to_msecs(jiffies))
-+
-+static inline unsigned int
-+jbd_time_diff(unsigned int start, unsigned int end)
-+{
-+ if (unlikely(start > end))
-+ end = end + (~0UL - start);
-+ else
-+ end -= start;
-+ return end;
-+}
-+
- /**
- * struct journal_s - The journal_s type is the concrete type associated with
- * journal_t.
-@@ -828,6 +904,16 @@ struct journal_s
- struct jbd_revoke_table_s *j_revoke_table[2];
-
- /*
-+ *
-+ */
-+ struct transaction_stats_s *j_history;
-+ int j_history_max;
-+ int j_history_cur;
-+ spinlock_t j_history_lock;
-+ struct proc_dir_entry *j_proc_entry;
-+ struct transaction_stats_s j_stats;
-+
-+ /*
- * An opaque pointer to fs-private information. ext3 puts its
- * superblock pointer here
- */
-Index: linux-2.6.9/fs/jbd/commit.c
-===================================================================
---- linux-2.6.9.orig/fs/jbd/commit.c
-+++ linux-2.6.9/fs/jbd/commit.c
-@@ -21,6 +21,7 @@
- #include <linux/mm.h>
- #include <linux/pagemap.h>
- #include <linux/smp_lock.h>
-+#include <linux/jiffies.h>
-
- /*
- * Default IO end handler for temporary BJ_IO buffer_heads.
-@@ -101,6 +102,7 @@ static int inverted_lock(journal_t *jour
- */
- void journal_commit_transaction(journal_t *journal)
- {
-+ struct transaction_stats_s stats;
- transaction_t *commit_transaction;
- struct journal_head *jh, *new_jh, *descriptor;
- struct buffer_head *wbuf[64];
-@@ -147,6 +149,11 @@ void journal_commit_transaction(journal_
- spin_lock(&journal->j_state_lock);
- commit_transaction->t_state = T_LOCKED;
-
-+ stats.ts_wait = commit_transaction->t_max_wait;
-+ stats.ts_locked = CURRENT_MSECS;
-+ stats.ts_running = jbd_time_diff(commit_transaction->t_start,
-+ stats.ts_locked);
-+
- spin_lock(&commit_transaction->t_handle_lock);
- while (commit_transaction->t_updates) {
- DEFINE_WAIT(wait);
-@@ -219,6 +226,9 @@ void journal_commit_transaction(journal_
- */
- journal_switch_revoke_table(journal);
-
-+ stats.ts_flushing = CURRENT_MSECS;
-+ stats.ts_locked = jbd_time_diff(stats.ts_locked, stats.ts_flushing);
-+
- commit_transaction->t_state = T_FLUSH;
- journal->j_committing_transaction = commit_transaction;
- journal->j_running_transaction = NULL;
-@@ -365,6 +375,11 @@ write_out_data:
- */
- commit_transaction->t_state = T_COMMIT;
-
-+ stats.ts_logging = CURRENT_MSECS;
-+ stats.ts_flushing = jbd_time_diff(stats.ts_flushing, stats.ts_logging);
-+ stats.ts_blocks = commit_transaction->t_outstanding_credits;
-+ stats.ts_blocks_logged = 0;
-+
- descriptor = NULL;
- bufs = 0;
- while (commit_transaction->t_buffers) {
-@@ -513,6 +528,7 @@ start_journal_io:
- submit_bh(WRITE, bh);
- }
- cond_resched();
-+ stats.ts_blocks_logged += bufs;
-
- /* Force a new descriptor to be generated next
- time round the loop. */
-@@ -767,6 +783,7 @@ restart_loop:
- cp_transaction = jh->b_cp_transaction;
- if (cp_transaction) {
- JBUFFER_TRACE(jh, "remove from old cp transaction");
-+ cp_transaction->t_chp_stats.cs_dropped++;
- __journal_remove_checkpoint(jh);
- }
-
-@@ -816,6 +833,37 @@ restart_loop:
- }
- cond_resched_lock(&journal->j_list_lock);
- }
-+
-+ commit_transaction->t_start = CURRENT_MSECS;
-+ stats.ts_logging = jbd_time_diff(stats.ts_logging,
-+ commit_transaction->t_start);
-+
-+ /*
-+ * File the transaction for history
-+ */
-+ stats.ts_type = JBD_STATS_RUN;
-+ stats.ts_tid = commit_transaction->t_tid;
-+ stats.ts_handle_count = commit_transaction->t_handle_count;
-+ spin_lock(&journal->j_history_lock);
-+ memcpy(journal->j_history + journal->j_history_cur, &stats,
-+ sizeof(stats));
-+ if (++journal->j_history_cur == journal->j_history_max)
-+ journal->j_history_cur = 0;
-+
-+ /*
-+ * Calculate overall stats
-+ */
-+ journal->j_stats.ts_tid++;
-+ journal->j_stats.ts_wait += stats.ts_wait;
-+ journal->j_stats.ts_running += stats.ts_running;
-+ journal->j_stats.ts_locked += stats.ts_locked;
-+ journal->j_stats.ts_flushing += stats.ts_flushing;
-+ journal->j_stats.ts_logging += stats.ts_logging;
-+ journal->j_stats.ts_handle_count += stats.ts_handle_count;
-+ journal->j_stats.ts_blocks += stats.ts_blocks;
-+ journal->j_stats.ts_blocks_logged += stats.ts_blocks_logged;
-+ spin_unlock(&journal->j_history_lock);
-+
- spin_unlock(&journal->j_list_lock);
- /*
- * This is a bit sleazy. We borrow j_list_lock to protect
-Index: linux-2.6.9/fs/jbd/checkpoint.c
-===================================================================
---- linux-2.6.9.orig/fs/jbd/checkpoint.c
-+++ linux-2.6.9/fs/jbd/checkpoint.c
-@@ -126,7 +127,8 @@
- * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it
- */
- static int __process_buffer(journal_t *journal, struct journal_head *jh,
-- struct buffer_head **bhs, int *batch_count)
-+ struct buffer_head **bhs, int *batch_count,
-+ transaction_t *transaction)
- {
- struct buffer_head *bh = jh2bh(jh);
- int ret = 0;
-@@ -166,6 +166,7 @@
- transaction_t *t = jh->b_transaction;
- tid_t tid = t->t_tid;
-
-+ transaction->t_chp_stats.cs_forced_to_close++;
- spin_unlock(&journal->j_list_lock);
- jbd_unlock_bh_state(bh);
- log_start_commit(journal, tid);
-@@ -247,6 +248,7 @@
- bhs[*batch_count] = bh;
- __buffer_relink_io(jh);
- jbd_unlock_bh_state(bh);
-+ transaction->t_chp_stats.cs_written++;
- (*batch_count)++;
- if (*batch_count == NR_BATCH) {
- spin_unlock(&journal->j_list_lock);
-@@ -315,6 +317,8 @@ int log_do_checkpoint(journal_t *journal
- if (!journal->j_checkpoint_transactions)
- goto out;
- transaction = journal->j_checkpoint_transactions;
-+ if (transaction->t_chp_stats.cs_chp_time == 0)
-+ transaction->t_chp_stats.cs_chp_time = CURRENT_MSECS;
- this_tid = transaction->t_tid;
- restart:
- /*
-@@ -331,7 +335,8 @@ int log_do_checkpoint(journal_t *journal
- retry = 1;
- break;
- }
-- retry = __process_buffer(journal, jh, bhs,&batch_count);
-+ retry = __process_buffer(journal, jh, bhs,&batch_count,
-+ transaction);
- }
-
- if (batch_count) {
-@@ -597,6 +602,8 @@ void __journal_insert_checkpoint(struct
-
- void __journal_drop_transaction(journal_t *journal, transaction_t *transaction)
- {
-+ struct transaction_stats_s stats;
-+
- assert_spin_locked(&journal->j_list_lock);
- if (transaction->t_cpnext) {
- transaction->t_cpnext->t_cpprev = transaction->t_cpprev;
-@@ -622,5 +629,25 @@ void __journal_drop_transaction(journal_
- J_ASSERT(journal->j_running_transaction != transaction);
-
- jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid);
-+
-+ /*
-+ * File the transaction for history
-+ */
-+ if (transaction->t_chp_stats.cs_written != 0 ||
-+ transaction->t_chp_stats.cs_chp_time != 0) {
-+ stats.ts_type = JBD_STATS_CHECKPOINT;
-+ stats.ts_tid = transaction->t_tid;
-+ stats.u.chp = transaction->t_chp_stats;
-+ if (stats.ts_chp_time)
-+ stats.ts_chp_time =
-+ jbd_time_diff(stats.ts_chp_time, CURRENT_MSECS);
-+ spin_lock(&journal->j_history_lock);
-+ memcpy(journal->j_history + journal->j_history_cur, &stats,
-+ sizeof(stats));
-+ if (++journal->j_history_cur == journal->j_history_max)
-+ journal->j_history_cur = 0;
-+ spin_unlock(&journal->j_history_lock);
-+ }
-+
- kfree(transaction);
- }
-Index: linux-2.6.9/fs/jbd/transaction.c
-===================================================================
---- linux-2.6.9.orig/fs/jbd/transaction.c
-+++ linux-2.6.9/fs/jbd/transaction.c
-@@ -60,6 +60,8 @@ get_transaction(journal_t *journal, tran
-
- J_ASSERT(journal->j_running_transaction == NULL);
- journal->j_running_transaction = transaction;
-+ transaction->t_max_wait = 0;
-+ transaction->t_start = CURRENT_MSECS;
-
- return transaction;
- }
-@@ -86,6 +88,7 @@ static int start_this_handle(journal_t *
- int nblocks = handle->h_buffer_credits;
- transaction_t *new_transaction = NULL;
- int ret = 0;
-+ unsigned long ts = CURRENT_MSECS;
-
- if (nblocks > journal->j_max_transaction_buffers) {
- printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n",
-@@ -219,6 +222,12 @@ repeat_locked:
- /* OK, account for the buffers that this operation expects to
- * use and add the handle to the running transaction. */
-
-+ if (time_after(transaction->t_start, ts)) {
-+ ts = jbd_time_diff(ts, transaction->t_start);
-+ if (ts > transaction->t_max_wait)
-+ transaction->t_max_wait= ts;
-+ }
-+
- handle->h_transaction = transaction;
- transaction->t_outstanding_credits += nblocks;
- transaction->t_updates++;
-Index: linux-2.6.9/fs/jbd/journal.c
-===================================================================
---- linux-2.6.9.orig/fs/jbd/journal.c
-+++ linux-2.6.9/fs/jbd/journal.c
-@@ -36,6 +36,7 @@
- #include <asm/uaccess.h>
- #include <asm/page.h>
- #include <linux/proc_fs.h>
-+#include <linux/seq_file.h>
-
- EXPORT_SYMBOL(journal_start);
- EXPORT_SYMBOL(journal_restart);
-@@ -649,6 +650,300 @@ struct journal_head *journal_get_descrip
- return journal_add_journal_head(bh);
- }
-
-+struct jbd_stats_proc_session {
-+ journal_t *journal;
-+ struct transaction_stats_s *stats;
-+ int start;
-+ int max;
-+};
-+
-+static void *jbd_history_skip_empty(struct jbd_stats_proc_session *s,
-+ struct transaction_stats_s *ts,
-+ int first)
-+{
-+ if (ts == s->stats + s->max)
-+ ts = s->stats;
-+ if (!first && ts == s->stats + s->start)
-+ return NULL;
-+ while (ts->ts_type == 0) {
-+ ts++;
-+ if (ts == s->stats + s->max)
-+ ts = s->stats;
-+ if (ts == s->stats + s->start)
-+ return NULL;
-+ }
-+ return ts;
-+
-+}
-+
-+static void *jbd_seq_history_start(struct seq_file *seq, loff_t *pos)
-+{
-+ struct jbd_stats_proc_session *s = seq->private;
-+ struct transaction_stats_s *ts;
-+ int l = *pos;
-+
-+ if (l == 0)
-+ return SEQ_START_TOKEN;
-+ ts = jbd_history_skip_empty(s, s->stats + s->start, 1);
-+ if (!ts)
-+ return NULL;
-+ while (--l && (ts = jbd_history_skip_empty(s, ++ts, 0)) != NULL);
-+ return ts;
-+}
-+
-+static void *jbd_seq_history_next(struct seq_file *seq, void *v, loff_t *pos)
-+{
-+ struct jbd_stats_proc_session *s = seq->private;
-+ struct transaction_stats_s *ts = v;
-+
-+ ++*pos;
-+ if (v == SEQ_START_TOKEN)
-+ return jbd_history_skip_empty(s, s->stats + s->start, 1);
-+ else
-+ return jbd_history_skip_empty(s, ++ts, 0);
-+}
-+
-+static int jbd_seq_history_show(struct seq_file *seq, void *v)
-+{
-+ struct transaction_stats_s *ts = v;
-+ if (v == SEQ_START_TOKEN) {
-+ seq_printf(seq, "%-4s %-5s %-5s %-5s %-5s %-5s %-5s %-6s %-5s "
-+ "%-5s %-5s %-5s %-5s %-5s\n", "R/C", "tid",
-+ "wait", "run", "lock", "flush", "log", "hndls",
-+ "block", "inlog", "ctime", "write", "drop",
-+ "close");
-+ return 0;
-+ }
-+ if (ts->ts_type == JBD_STATS_RUN)
-+ seq_printf(seq, "%-4s %-5lu %-5lu %-5lu %-5lu %-5lu %-5lu "
-+ "%-6lu %-5lu %-5lu\n", "R", ts->ts_tid,
-+ ts->ts_wait, ts->ts_running, ts->ts_locked,
-+ ts->ts_flushing, ts->ts_logging,
-+ ts->ts_handle_count, ts->ts_blocks,
-+ ts->ts_blocks_logged);
-+ else if (ts->ts_type == JBD_STATS_CHECKPOINT)
-+ seq_printf(seq, "%-4s %-5lu %48s %-5lu %-5lu %-5lu %-5lu\n",
-+ "C", ts->ts_tid, " ", ts->ts_chp_time,
-+ ts->ts_written, ts->ts_dropped,
-+ ts->ts_forced_to_close);
-+ else
-+ J_ASSERT(0);
-+ return 0;
-+}
-+
-+static void jbd_seq_history_stop(struct seq_file *seq, void *v)
-+{
-+}
-+
-+static struct seq_operations jbd_seq_history_ops = {
-+ .start = jbd_seq_history_start,
-+ .next = jbd_seq_history_next,
-+ .stop = jbd_seq_history_stop,
-+ .show = jbd_seq_history_show,
-+};
-+
-+static int jbd_seq_history_open(struct inode *inode, struct file *file)
-+{
-+ journal_t *journal = PDE(inode)->data;
-+ struct jbd_stats_proc_session *s;
-+ int rc, size;
-+
-+ s = kmalloc(sizeof(*s), GFP_KERNEL);
-+ if (s == NULL)
-+ return -EIO;
-+ size = sizeof(struct transaction_stats_s) * journal->j_history_max;
-+ s->stats = kmalloc(size, GFP_KERNEL);
-+ if (s->stats == NULL) {
-+ kfree(s);
-+ return -EIO;
-+ }
-+ spin_lock(&journal->j_history_lock);
-+ memcpy(s->stats, journal->j_history, size);
-+ s->max = journal->j_history_max;
-+ s->start = journal->j_history_cur % s->max;
-+ spin_unlock(&journal->j_history_lock);
-+
-+ rc = seq_open(file, &jbd_seq_history_ops);
-+ if (rc == 0) {
-+ struct seq_file *m = (struct seq_file *)file->private_data;
-+ m->private = s;
-+ } else {
-+ kfree(s->stats);
-+ kfree(s);
-+ }
-+ return rc;
-+
-+}
-+
-+static int jbd_seq_history_release(struct inode *inode, struct file *file)
-+{
-+ struct seq_file *seq = (struct seq_file *)file->private_data;
-+ struct jbd_stats_proc_session *s = seq->private;
-+ kfree(s->stats);
-+ kfree(s);
-+ return seq_release(inode, file);
-+}
-+
-+static struct file_operations jbd_seq_history_fops = {
-+ .owner = THIS_MODULE,
-+ .open = jbd_seq_history_open,
-+ .read = seq_read,
-+ .llseek = seq_lseek,
-+ .release = jbd_seq_history_release,
-+};
-+
-+static void *jbd_seq_info_start(struct seq_file *seq, loff_t *pos)
-+{
-+ return *pos ? NULL : SEQ_START_TOKEN;
-+}
-+
-+static void *jbd_seq_info_next(struct seq_file *seq, void *v, loff_t *pos)
-+{
-+ return NULL;
-+}
-+
-+static int jbd_seq_info_show(struct seq_file *seq, void *v)
-+{
-+ struct jbd_stats_proc_session *s = seq->private;
-+ if (v != SEQ_START_TOKEN)
-+ return 0;
-+ seq_printf(seq, "%lu transaction, each upto %u blocks\n",
-+ s->stats->ts_tid,
-+ s->journal->j_max_transaction_buffers);
-+ if (s->stats->ts_tid == 0)
-+ return 0;
-+ seq_printf(seq, "average: \n %lums waiting for transaction\n",
-+ s->stats->ts_wait / s->stats->ts_tid);
-+ seq_printf(seq, " %lums running transaction\n",
-+ s->stats->ts_running / s->stats->ts_tid);
-+ seq_printf(seq, " %lums transaction was being locked\n",
-+ s->stats->ts_locked / s->stats->ts_tid);
-+ seq_printf(seq, " %lums flushing data (in ordered mode)\n",
-+ s->stats->ts_flushing / s->stats->ts_tid);
-+ seq_printf(seq, " %lums logging transaction\n",
-+ s->stats->ts_logging / s->stats->ts_tid);
-+ seq_printf(seq, " %lu handles per transaction\n",
-+ s->stats->ts_handle_count / s->stats->ts_tid);
-+ seq_printf(seq, " %lu blocks per transaction\n",
-+ s->stats->ts_blocks / s->stats->ts_tid);
-+ seq_printf(seq, " %lu logged blocks per transaction\n",
-+ s->stats->ts_blocks_logged / s->stats->ts_tid);
-+ return 0;
-+}
-+
-+static void jbd_seq_info_stop(struct seq_file *seq, void *v)
-+{
-+}
-+
-+static struct seq_operations jbd_seq_info_ops = {
-+ .start = jbd_seq_info_start,
-+ .next = jbd_seq_info_next,
-+ .stop = jbd_seq_info_stop,
-+ .show = jbd_seq_info_show,
-+};
-+
-+static int jbd_seq_info_open(struct inode *inode, struct file *file)
-+{
-+ journal_t *journal = PDE(inode)->data;
-+ struct jbd_stats_proc_session *s;
-+ int rc, size;
-+
-+ s = kmalloc(sizeof(*s), GFP_KERNEL);
-+ if (s == NULL)
-+ return -EIO;
-+ size = sizeof(struct transaction_stats_s);
-+ s->stats = kmalloc(size, GFP_KERNEL);
-+ if (s->stats == NULL) {
-+ kfree(s);
-+ return -EIO;
-+ }
-+ spin_lock(&journal->j_history_lock);
-+ memcpy(s->stats, &journal->j_stats, size);
-+ s->journal = journal;
-+ spin_unlock(&journal->j_history_lock);
-+
-+ rc = seq_open(file, &jbd_seq_info_ops);
-+ if (rc == 0) {
-+ struct seq_file *m = (struct seq_file *)file->private_data;
-+ m->private = s;
-+ } else {
-+ kfree(s->stats);
-+ kfree(s);
-+ }
-+ return rc;
-+
-+}
-+
-+static int jbd_seq_info_release(struct inode *inode, struct file *file)
-+{
-+ struct seq_file *seq = (struct seq_file *)file->private_data;
-+ struct jbd_stats_proc_session *s = seq->private;
-+ kfree(s->stats);
-+ kfree(s);
-+ return seq_release(inode, file);
-+}
-+
-+static struct file_operations jbd_seq_info_fops = {
-+ .owner = THIS_MODULE,
-+ .open = jbd_seq_info_open,
-+ .read = seq_read,
-+ .llseek = seq_lseek,
-+ .release = jbd_seq_info_release,
-+};
-+
-+static struct proc_dir_entry *proc_jbd_stats = NULL;
-+
-+static void jbd_stats_proc_init(journal_t *journal)
-+{
-+ char name[64];
-+
-+ snprintf(name, sizeof(name) - 1, "%s", bdevname(journal->j_dev, name));
-+ journal->j_proc_entry = proc_mkdir(name, proc_jbd_stats);
-+ if (journal->j_proc_entry) {
-+ struct proc_dir_entry *p;
-+ p = create_proc_entry("history", S_IRUGO,
-+ journal->j_proc_entry);
-+ if (p) {
-+ p->proc_fops = &jbd_seq_history_fops;
-+ p->data = journal;
-+ p = create_proc_entry("info", S_IRUGO,
-+ journal->j_proc_entry);
-+ if (p) {
-+ p->proc_fops = &jbd_seq_info_fops;
-+ p->data = journal;
-+ }
-+ }
-+ }
-+}
-+
-+static void jbd_stats_proc_exit(journal_t *journal)
-+{
-+ char name[64];
-+
-+ snprintf(name, sizeof(name) - 1, "%s", bdevname(journal->j_dev, name));
-+ remove_proc_entry("info", journal->j_proc_entry);
-+ remove_proc_entry("history", journal->j_proc_entry);
-+ remove_proc_entry(name, proc_jbd_stats);
-+}
-+
-+static void journal_init_stats(journal_t *journal)
-+{
-+ int size;
-+
-+ if (proc_jbd_stats == NULL)
-+ return;
-+
-+ journal->j_history_max = 100;
-+ size = sizeof(struct transaction_stats_s) * journal->j_history_max;
-+ journal->j_history = kmalloc(size, GFP_KERNEL);
-+ if (journal->j_history == NULL) {
-+ journal->j_history_max = 0;
-+ return;
-+ }
-+ memset(journal->j_history, 0, size);
-+ spin_lock_init(&journal->j_history_lock);
-+}
-+
- /*
- * Management for journal control blocks: functions to create and
- * destroy journal_t structures, and to initialise and read existing
-@@ -691,6 +986,9 @@ static journal_t * journal_init_common (
- kfree(journal);
- goto fail;
- }
-+
-+ journal_init_stats(journal);
-+
- return journal;
- fail:
- return NULL;
-@@ -733,6 +1031,7 @@ journal_t * journal_init_dev(struct bloc
- journal->j_blk_offset = start;
- journal->j_maxlen = len;
- journal->j_blocksize = blocksize;
-+ jbd_stats_proc_init(journal);
-
- bh = __getblk(journal->j_dev, start, journal->j_blocksize);
- J_ASSERT(bh != NULL);
-@@ -770,6 +1069,7 @@ journal_t * journal_init_inode (struct i
-
- journal->j_maxlen = inode->i_size >> inode->i_sb->s_blocksize_bits;
- journal->j_blocksize = inode->i_sb->s_blocksize;
-+ jbd_stats_proc_init(journal);
-
- err = journal_bmap(journal, 0, &blocknr);
- /* If that failed, give up */
-@@ -1140,6 +1440,8 @@ void journal_destroy(journal_t *journal)
- brelse(journal->j_sb_buffer);
- }
-
-+ if (journal->j_proc_entry)
-+ jbd_stats_proc_exit(journal);
- if (journal->j_inode)
- iput(journal->j_inode);
- if (journal->j_revoke)
-@@ -1896,6 +2198,28 @@ static void __exit remove_jbd_proc_entry
-
- #endif
-
-+#if defined(CONFIG_PROC_FS)
-+
-+#define JBD_STATS_PROC_NAME "fs/jbd"
-+
-+static void __init create_jbd_stats_proc_entry(void)
-+{
-+ proc_jbd_stats = proc_mkdir(JBD_STATS_PROC_NAME, NULL);
-+}
-+
-+static void __exit remove_jbd_stats_proc_entry(void)
-+{
-+ if (proc_jbd_stats)
-+ remove_proc_entry(JBD_STATS_PROC_NAME, NULL);
-+}
-+
-+#else
-+
-+#define create_jbd_stats_proc_entry() do {} while (0)
-+#define remove_jbd_stats_proc_entry() do {} while (0)
-+
-+#endif
-+
- kmem_cache_t *jbd_handle_cache;
-
- static int __init journal_init_handle_cache(void)
-@@ -1950,6 +2274,7 @@ static int __init journal_init(void)
- if (ret != 0)
- journal_destroy_caches();
- create_jbd_proc_entry();
-+ create_jbd_stats_proc_entry();
- return ret;
- }
-
-@@ -1961,6 +2286,7 @@ static void __exit journal_exit(void)
- printk(KERN_EMERG "JBD: leaked %d journal_heads!\n", n);
- #endif
- remove_jbd_proc_entry();
-+ remove_jbd_stats_proc_entry();
- journal_destroy_caches();
- }
-