Whamcloud - gitweb
b=13454
authorkalpak <kalpak>
Thu, 11 Oct 2007 23:25:15 +0000 (23:25 +0000)
committerkalpak <kalpak>
Thu, 11 Oct 2007 23:25:15 +0000 (23:25 +0000)
i=alex, kalpak

rebase jbd-stats patch for rhel5 and 2.6.18

lustre/ChangeLog
lustre/kernel_patches/patches/jbd-stats-2.6-rhel5.patch [new file with mode: 0644]
lustre/kernel_patches/series/2.6-rhel5.series
lustre/kernel_patches/series/2.6.18-vanilla.series

index 41fb85f..479eb5b 100644 (file)
@@ -385,6 +385,10 @@ Details    : When running with O_DIRECT I/O, neither the client rpc_stats nor
              read_ahead_stats were updated. copied the stats section from
              osc_send_oap_rpc() into async_internal().
 
+Severity   : normal
+Bugzilla   : 13454
+Description: Add jbd statistics patch for RHEL5 and 2.6.18-vanilla
+
 
 --------------------------------------------------------------------------------
 
diff --git a/lustre/kernel_patches/patches/jbd-stats-2.6-rhel5.patch b/lustre/kernel_patches/patches/jbd-stats-2.6-rhel5.patch
new file mode 100644 (file)
index 0000000..50fb6f5
--- /dev/null
@@ -0,0 +1,744 @@
+Index: linux-2.6.18-8.1.8/include/linux/jbd.h
+===================================================================
+--- linux-2.6.18-8.1.8.orig/include/linux/jbd.h        2007-08-28 22:22:10.000000000 +0200
++++ linux-2.6.18-8.1.8/include/linux/jbd.h     2007-08-28 22:22:29.000000000 +0200
+@@ -455,6 +455,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:
+  *
+@@ -592,6 +602,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]
+        */
+@@ -631,6 +656,57 @@ struct transaction_s 
+       struct list_head        t_jcb;
+ };
++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.
+@@ -884,6 +960,16 @@ struct journal_s
+       pid_t                   j_last_sync_writer;
+       /*
++       *
++       */
++      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.18-8.1.8/fs/jbd/transaction.c
+===================================================================
+--- linux-2.6.18-8.1.8.orig/fs/jbd/transaction.c       2007-08-28 22:22:10.000000000 +0200
++++ linux-2.6.18-8.1.8/fs/jbd/transaction.c    2007-08-28 22:22:29.000000000 +0200
+@@ -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.18-8.1.8/fs/jbd/journal.c
+===================================================================
+--- linux-2.6.18-8.1.8.orig/fs/jbd/journal.c   2007-08-28 22:22:10.000000000 +0200
++++ linux-2.6.18-8.1.8/fs/jbd/journal.c        2007-08-28 22:22:29.000000000 +0200
+@@ -36,6 +36,7 @@
+ #include <linux/kthread.h>
+ #include <linux/poison.h>
+ #include <linux/proc_fs.h>
++#include <linux/seq_file.h>
+ #include <asm/uaccess.h>
+ #include <asm/page.h>
+@@ -639,6 +640,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 == 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 == 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
+@@ -681,6 +976,9 @@ static journal_t * journal_init_common (
+               kfree(journal);
+               goto fail;
+       }
++
++      journal_init_stats(journal);
++
+       return journal;
+ fail:
+       return NULL;
+@@ -724,6 +1022,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);
+@@ -773,6 +1072,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);
+       /* journal descriptor can store up to n blocks -bzzz */
+       n = journal->j_blocksize / sizeof(journal_block_tag_t);
+@@ -1161,6 +1461,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)
+@@ -2027,6 +2329,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)
+@@ -2090,6 +2414,7 @@ static int __init journal_init(void)
+       if (ret != 0)
+               journal_destroy_caches();
+       create_jbd_proc_entry();
++      create_jbd_stats_proc_entry();
+       return ret;
+ }
+@@ -2101,6 +2426,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();
+ }
+Index: linux-2.6.18-8.1.8/fs/jbd/checkpoint.c
+===================================================================
+--- linux-2.6.18-8.1.8.orig/fs/jbd/checkpoint.c        2007-08-28 22:22:10.000000000 +0200
++++ linux-2.6.18-8.1.8/fs/jbd/checkpoint.c     2007-08-28 22:23:23.000000000 +0200
+@@ -231,7 +231,7 @@ __flush_batch(journal_t *journal, struct
+  * 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;
+@@ -249,6 +249,7 @@ static int __process_buffer(journal_t *j
+               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);
+@@ -278,6 +279,7 @@ static int __process_buffer(journal_t *j
+               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);
+@@ -321,6 +323,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:
+       /*
+@@ -345,7 +349,8 @@ restart:
+                               retry = 1;
+                               break;
+                       }
+-                      retry = __process_buffer(journal, jh, bhs,&batch_count);
++                      retry = __process_buffer(journal, jh, bhs,&batch_count,
++                                               transaction);
+                       if (!retry && lock_need_resched(&journal->j_list_lock)){
+                               spin_unlock(&journal->j_list_lock);
+                               retry = 1;
+@@ -667,6 +672,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;
+@@ -693,5 +700,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.18-8.1.8/fs/jbd/commit.c
+===================================================================
+--- linux-2.6.18-8.1.8.orig/fs/jbd/commit.c    2007-08-28 22:22:10.000000000 +0200
++++ linux-2.6.18-8.1.8/fs/jbd/commit.c 2007-08-28 22:22:29.000000000 +0200
+@@ -13,6 +13,7 @@
+  * part of the ext2fs journaling system.
+  */
++#include <linux/jiffies.h>
+ #include <linux/time.h>
+ #include <linux/fs.h>
+ #include <linux/jbd.h>
+@@ -23,6 +24,7 @@
+ #include <linux/smp_lock.h>
+ #include <linux/crc32.h>
++
+ /*
+  * Default IO end handler for temporary BJ_IO buffer_heads.
+  */
+@@ -355,6 +357,7 @@ write_out_data:
+  */
+ 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 = journal->j_wbuf;
+@@ -403,6 +406,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);
+@@ -473,6 +481,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;
+@@ -540,6 +551,11 @@ void journal_commit_transaction(journal_
+        */
+       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) {
+@@ -698,6 +714,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. */
+@@ -915,6 +932,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);
+               }
+@@ -989,6 +1007,36 @@ restart_loop:
+       J_ASSERT(commit_transaction->t_state == T_COMMIT);
++      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);
++
+       commit_transaction->t_state = T_FINISHED;
+       J_ASSERT(commit_transaction == journal->j_committing_transaction);
+       journal->j_commit_sequence = commit_transaction->t_tid;
+
index 076164b..1d46583 100644 (file)
@@ -9,3 +9,4 @@ export-2.6.18-vanilla.patch
 export-show_task-2.6.18-vanilla.patch
 sd_iostats-2.6-rhel4.patch
 export_symbol_numa-2.6-fc5.patch
+jbd-stats-2.6-rhel5.patch
index bca2d16..8dabcf6 100644 (file)
@@ -13,3 +13,4 @@ sd_iostats-2.6-rhel4.patch
 export_symbol_numa-2.6.18.patch
 jbd-16tb-overflow-fixes.patch
 jbd-check-for-unmapped-buffer.patch
+jbd-stats-2.6-rhel5.patch