Whamcloud - gitweb
c770722a0444c5068beede2e83067bf5efc6b376
[fs/lustre-release.git] / lustre / kernel_patches / patches / jbd-stats-2.6-rhel5.patch
1 Index: linux-2.6.18-8.1.8/include/linux/jbd.h
2 ===================================================================
3 --- linux-2.6.18-8.1.8.orig/include/linux/jbd.h 2007-08-28 22:22:10.000000000 +0200
4 +++ linux-2.6.18-8.1.8/include/linux/jbd.h      2007-08-28 22:22:29.000000000 +0200
5 @@ -455,6 +455,16 @@ struct handle_s 
6  };
7  
8  
9 +/*
10 + * Some stats for checkpoint phase
11 + */
12 +struct transaction_chp_stats_s {
13 +       unsigned long           cs_chp_time;
14 +       unsigned long           cs_forced_to_close;
15 +       unsigned long           cs_written;
16 +       unsigned long           cs_dropped;
17 +};
18 +
19  /* The transaction_t type is the guts of the journaling mechanism.  It
20   * tracks a compound transaction through its various states:
21   *
22 @@ -592,6 +602,21 @@ struct transaction_s 
23         spinlock_t              t_handle_lock;
24  
25         /*
26 +        * Longest time some handle had to wait for running transaction
27 +        */
28 +       unsigned long           t_max_wait;
29 +
30 +       /*
31 +        * When transaction started
32 +        */
33 +       unsigned long           t_start;
34 +
35 +       /*
36 +        * Checkpointing stats [j_checkpoint_sem]
37 +        */
38 +       struct transaction_chp_stats_s t_chp_stats;
39 +
40 +       /*
41          * Number of outstanding updates running on this transaction
42          * [t_handle_lock]
43          */
44 @@ -631,6 +656,57 @@ struct transaction_s 
45         struct list_head        t_jcb;
46  };
47  
48 +struct transaction_run_stats_s {
49 +       unsigned long           rs_wait;
50 +       unsigned long           rs_running;
51 +       unsigned long           rs_locked;
52 +       unsigned long           rs_flushing;
53 +       unsigned long           rs_logging;
54 +
55 +       unsigned long           rs_handle_count;
56 +       unsigned long           rs_blocks;
57 +       unsigned long           rs_blocks_logged;
58 +};
59 +
60 +struct transaction_stats_s
61 +{
62 +       int                     ts_type;
63 +       unsigned long           ts_tid;
64 +       union {
65 +               struct transaction_run_stats_s run;
66 +               struct transaction_chp_stats_s chp;
67 +       } u;
68 +};
69 +
70 +#define JBD_STATS_RUN          1
71 +#define JBD_STATS_CHECKPOINT   2
72 +
73 +#define ts_wait                        u.run.rs_wait
74 +#define ts_running             u.run.rs_running
75 +#define ts_locked              u.run.rs_locked
76 +#define ts_flushing            u.run.rs_flushing
77 +#define ts_logging             u.run.rs_logging
78 +#define ts_handle_count                u.run.rs_handle_count
79 +#define ts_blocks              u.run.rs_blocks
80 +#define ts_blocks_logged       u.run.rs_blocks_logged
81 +
82 +#define ts_chp_time            u.chp.cs_chp_time
83 +#define ts_forced_to_close     u.chp.cs_forced_to_close
84 +#define ts_written             u.chp.cs_written
85 +#define ts_dropped             u.chp.cs_dropped
86 +
87 +#define CURRENT_MSECS          (jiffies_to_msecs(jiffies))
88 +
89 +static inline unsigned int
90 +jbd_time_diff(unsigned int start, unsigned int end)
91 +{
92 +       if (unlikely(start > end))
93 +               end = end + (~0UL - start);
94 +       else
95 +               end -= start;
96 +       return end;
97 +}
98 +
99  /**
100   * struct journal_s - The journal_s type is the concrete type associated with
101   *     journal_t.
102 @@ -884,6 +960,16 @@ struct journal_s
103         pid_t                   j_last_sync_writer;
104  
105         /*
106 +        *
107 +        */
108 +       struct transaction_stats_s *j_history;
109 +       int                     j_history_max;
110 +       int                     j_history_cur;
111 +       spinlock_t              j_history_lock;
112 +       struct proc_dir_entry   *j_proc_entry;
113 +       struct transaction_stats_s j_stats;
114 +
115 +       /*
116          * An opaque pointer to fs-private information.  ext3 puts its
117          * superblock pointer here
118          */
119 Index: linux-2.6.18-8.1.8/fs/jbd/transaction.c
120 ===================================================================
121 --- linux-2.6.18-8.1.8.orig/fs/jbd/transaction.c        2007-08-28 22:22:10.000000000 +0200
122 +++ linux-2.6.18-8.1.8/fs/jbd/transaction.c     2007-08-28 22:22:29.000000000 +0200
123 @@ -60,6 +60,8 @@ get_transaction(journal_t *journal, tran
124  
125         J_ASSERT(journal->j_running_transaction == NULL);
126         journal->j_running_transaction = transaction;
127 +       transaction->t_max_wait = 0;
128 +       transaction->t_start = CURRENT_MSECS;
129  
130         return transaction;
131  }
132 @@ -86,6 +88,7 @@ static int start_this_handle(journal_t *
133         int nblocks = handle->h_buffer_credits;
134         transaction_t *new_transaction = NULL;
135         int ret = 0;
136 +       unsigned long ts = CURRENT_MSECS;
137  
138         if (nblocks > journal->j_max_transaction_buffers) {
139                 printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n",
140 @@ -219,6 +222,12 @@ repeat_locked:
141         /* OK, account for the buffers that this operation expects to
142          * use and add the handle to the running transaction. */
143  
144 +       if (time_after(transaction->t_start, ts)) {
145 +               ts = jbd_time_diff(ts, transaction->t_start);
146 +               if (ts > transaction->t_max_wait)
147 +                       transaction->t_max_wait= ts;
148 +       }
149 +
150         handle->h_transaction = transaction;
151         transaction->t_outstanding_credits += nblocks;
152         transaction->t_updates++;
153 Index: linux-2.6.18-8.1.8/fs/jbd/journal.c
154 ===================================================================
155 --- linux-2.6.18-8.1.8.orig/fs/jbd/journal.c    2007-08-28 22:22:10.000000000 +0200
156 +++ linux-2.6.18-8.1.8/fs/jbd/journal.c 2007-08-28 22:22:29.000000000 +0200
157 @@ -36,6 +36,7 @@
158  #include <linux/kthread.h>
159  #include <linux/poison.h>
160  #include <linux/proc_fs.h>
161 +#include <linux/seq_file.h>
162  
163  #include <asm/uaccess.h>
164  #include <asm/page.h>
165 @@ -639,6 +640,300 @@ struct journal_head *journal_get_descrip
166         return journal_add_journal_head(bh);
167  }
168  
169 +struct jbd_stats_proc_session {
170 +       journal_t *journal;
171 +       struct transaction_stats_s *stats;
172 +       int start;
173 +       int max;
174 +};
175 +
176 +static void *jbd_history_skip_empty(struct jbd_stats_proc_session *s,
177 +                                       struct transaction_stats_s *ts,
178 +                                       int first)
179 +{
180 +       if (ts == s->stats + s->max)
181 +               ts = s->stats;
182 +       if (!first && ts == s->stats + s->start)
183 +               return NULL;
184 +       while (ts->ts_type == 0) {
185 +               ts++;
186 +               if (ts == s->stats + s->max)
187 +                       ts = s->stats;
188 +               if (ts == s->stats + s->start)
189 +                       return NULL;
190 +       }
191 +       return ts;
192 +
193 +}
194 +
195 +static void *jbd_seq_history_start(struct seq_file *seq, loff_t *pos)
196 +{
197 +       struct jbd_stats_proc_session *s = seq->private;
198 +       struct transaction_stats_s *ts;
199 +       int l = *pos;
200 +
201 +       if (l == 0)
202 +               return SEQ_START_TOKEN;
203 +       ts = jbd_history_skip_empty(s, s->stats + s->start, 1);
204 +       if (!ts)
205 +               return NULL;
206 +       while (--l && (ts = jbd_history_skip_empty(s, ++ts, 0)) != NULL);
207 +       return ts;
208 +}
209 +
210 +static void *jbd_seq_history_next(struct seq_file *seq, void *v, loff_t *pos)
211 +{
212 +       struct jbd_stats_proc_session *s = seq->private;
213 +       struct transaction_stats_s *ts = v;
214 +
215 +       ++*pos;
216 +       if (v == SEQ_START_TOKEN)
217 +               return jbd_history_skip_empty(s, s->stats + s->start, 1);
218 +       else
219 +               return jbd_history_skip_empty(s, ++ts, 0);
220 +}
221 +
222 +static int jbd_seq_history_show(struct seq_file *seq, void *v)
223 +{
224 +       struct transaction_stats_s *ts = v;
225 +       if (v == SEQ_START_TOKEN) {
226 +               seq_printf(seq, "%-4s %-5s %-5s %-5s %-5s %-5s %-5s %-6s %-5s "
227 +                               "%-5s %-5s %-5s %-5s %-5s\n", "R/C", "tid",
228 +                               "wait", "run", "lock", "flush", "log", "hndls",
229 +                               "block", "inlog", "ctime", "write", "drop",
230 +                               "close");
231 +               return 0;
232 +       }
233 +       if (ts->ts_type == JBD_STATS_RUN)
234 +               seq_printf(seq, "%-4s %-5lu %-5lu %-5lu %-5lu %-5lu %-5lu "
235 +                               "%-6lu %-5lu %-5lu\n", "R", ts->ts_tid,
236 +                               ts->ts_wait, ts->ts_running, ts->ts_locked,
237 +                               ts->ts_flushing, ts->ts_logging,
238 +                               ts->ts_handle_count, ts->ts_blocks,
239 +                               ts->ts_blocks_logged);
240 +       else if (ts->ts_type == JBD_STATS_CHECKPOINT)
241 +               seq_printf(seq, "%-4s %-5lu %48s %-5lu %-5lu %-5lu %-5lu\n",
242 +                               "C", ts->ts_tid, " ", ts->ts_chp_time,
243 +                               ts->ts_written, ts->ts_dropped,
244 +                               ts->ts_forced_to_close);
245 +       else
246 +               J_ASSERT(0);
247 +       return 0;
248 +}
249 +
250 +static void jbd_seq_history_stop(struct seq_file *seq, void *v)
251 +{
252 +}
253 +
254 +static struct seq_operations jbd_seq_history_ops = {
255 +       .start  = jbd_seq_history_start,
256 +       .next   = jbd_seq_history_next,
257 +       .stop   = jbd_seq_history_stop,
258 +       .show   = jbd_seq_history_show,
259 +};
260 +
261 +static int jbd_seq_history_open(struct inode *inode, struct file *file)
262 +{
263 +       journal_t *journal = PDE(inode)->data;
264 +       struct jbd_stats_proc_session *s;
265 +       int rc, size;
266 +
267 +       s = kmalloc(sizeof(*s), GFP_KERNEL);
268 +       if (s == NULL)
269 +               return -EIO;
270 +       size = sizeof(struct transaction_stats_s) * journal->j_history_max;
271 +       s->stats = kmalloc(size, GFP_KERNEL);
272 +       if (s->stats == NULL) {
273 +               kfree(s);
274 +               return -EIO;
275 +       }
276 +       spin_lock(&journal->j_history_lock);
277 +       memcpy(s->stats, journal->j_history, size);
278 +       s->max = journal->j_history_max;
279 +       s->start = journal->j_history_cur % s->max;
280 +       spin_unlock(&journal->j_history_lock);
281 +
282 +       rc = seq_open(file, &jbd_seq_history_ops);
283 +       if (rc == 0) {
284 +               struct seq_file *m = (struct seq_file *)file->private_data;
285 +               m->private = s;
286 +       } else {
287 +               kfree(s->stats);
288 +               kfree(s);
289 +       }
290 +       return rc;
291 +
292 +}
293 +
294 +static int jbd_seq_history_release(struct inode *inode, struct file *file)
295 +{
296 +       struct seq_file *seq = (struct seq_file *)file->private_data;
297 +       struct jbd_stats_proc_session *s = seq->private;
298 +       kfree(s->stats);
299 +       kfree(s);
300 +       return seq_release(inode, file);
301 +}
302 +
303 +static struct file_operations jbd_seq_history_fops = {
304 +       .owner          = THIS_MODULE,
305 +       .open           = jbd_seq_history_open,
306 +       .read           = seq_read,
307 +       .llseek         = seq_lseek,
308 +       .release        = jbd_seq_history_release,
309 +};
310 +
311 +static void *jbd_seq_info_start(struct seq_file *seq, loff_t *pos)
312 +{
313 +       return *pos ? NULL : SEQ_START_TOKEN;
314 +}
315 +
316 +static void *jbd_seq_info_next(struct seq_file *seq, void *v, loff_t *pos)
317 +{
318 +       return NULL;
319 +}
320 +
321 +static int jbd_seq_info_show(struct seq_file *seq, void *v)
322 +{
323 +       struct jbd_stats_proc_session *s = seq->private;
324 +       if (v != SEQ_START_TOKEN)
325 +               return 0;
326 +       seq_printf(seq, "%lu transaction, each upto %u blocks\n",
327 +                       s->stats->ts_tid,
328 +                       s->journal->j_max_transaction_buffers);
329 +       if (s->stats->ts_tid == 0)
330 +               return 0;
331 +       seq_printf(seq, "average: \n  %lums waiting for transaction\n",
332 +                       s->stats->ts_wait / s->stats->ts_tid);
333 +       seq_printf(seq, "  %lums running transaction\n",
334 +                       s->stats->ts_running / s->stats->ts_tid);
335 +       seq_printf(seq, "  %lums transaction was being locked\n",
336 +                       s->stats->ts_locked / s->stats->ts_tid);
337 +       seq_printf(seq, "  %lums flushing data (in ordered mode)\n",
338 +                       s->stats->ts_flushing / s->stats->ts_tid);
339 +       seq_printf(seq, "  %lums logging transaction\n",
340 +                       s->stats->ts_logging / s->stats->ts_tid);
341 +       seq_printf(seq, "  %lu handles per transaction\n",
342 +                       s->stats->ts_handle_count / s->stats->ts_tid);
343 +       seq_printf(seq, "  %lu blocks per transaction\n",
344 +                       s->stats->ts_blocks / s->stats->ts_tid);
345 +       seq_printf(seq, "  %lu logged blocks per transaction\n",
346 +                       s->stats->ts_blocks_logged / s->stats->ts_tid);
347 +       return 0;
348 +}
349 +
350 +static void jbd_seq_info_stop(struct seq_file *seq, void *v)
351 +{
352 +}
353 +
354 +static struct seq_operations jbd_seq_info_ops = {
355 +       .start  = jbd_seq_info_start,
356 +       .next   = jbd_seq_info_next,
357 +       .stop   = jbd_seq_info_stop,
358 +       .show   = jbd_seq_info_show,
359 +};
360 +
361 +static int jbd_seq_info_open(struct inode *inode, struct file *file)
362 +{
363 +       journal_t *journal = PDE(inode)->data;
364 +       struct jbd_stats_proc_session *s;
365 +       int rc, size;
366 +
367 +       s = kmalloc(sizeof(*s), GFP_KERNEL);
368 +       if (s == NULL)
369 +               return -EIO;
370 +       size = sizeof(struct transaction_stats_s);
371 +       s->stats = kmalloc(size, GFP_KERNEL);
372 +       if (s->stats == NULL) {
373 +               kfree(s);
374 +               return -EIO;
375 +       }
376 +       spin_lock(&journal->j_history_lock);
377 +       memcpy(s->stats, &journal->j_stats, size);
378 +       s->journal = journal;
379 +       spin_unlock(&journal->j_history_lock);
380 +
381 +       rc = seq_open(file, &jbd_seq_info_ops);
382 +       if (rc == 0) {
383 +               struct seq_file *m = (struct seq_file *)file->private_data;
384 +               m->private = s;
385 +       } else {
386 +               kfree(s->stats);
387 +               kfree(s);
388 +       }
389 +       return rc;
390 +
391 +}
392 +
393 +static int jbd_seq_info_release(struct inode *inode, struct file *file)
394 +{
395 +       struct seq_file *seq = (struct seq_file *)file->private_data;
396 +       struct jbd_stats_proc_session *s = seq->private;
397 +       kfree(s->stats);
398 +       kfree(s);
399 +       return seq_release(inode, file);
400 +}
401 +
402 +static struct file_operations jbd_seq_info_fops = {
403 +       .owner          = THIS_MODULE,
404 +       .open           = jbd_seq_info_open,
405 +       .read           = seq_read,
406 +       .llseek         = seq_lseek,
407 +       .release        = jbd_seq_info_release,
408 +};
409 +
410 +static struct proc_dir_entry *proc_jbd_stats = NULL;
411 +
412 +static void jbd_stats_proc_init(journal_t *journal)
413 +{
414 +       char name[64];
415 +
416 +       snprintf(name, sizeof(name) - 1, "%s", bdevname(journal->j_dev, name));
417 +       journal->j_proc_entry = proc_mkdir(name, proc_jbd_stats);
418 +       if (journal->j_proc_entry) {
419 +               struct proc_dir_entry *p;
420 +               p = create_proc_entry("history", S_IRUGO,
421 +                               journal->j_proc_entry);
422 +               if (p) {
423 +                       p->proc_fops = &jbd_seq_history_fops;
424 +                       p->data = journal;
425 +                       p = create_proc_entry("info", S_IRUGO,
426 +                                               journal->j_proc_entry);
427 +                       if (p) {
428 +                               p->proc_fops = &jbd_seq_info_fops;
429 +                               p->data = journal;
430 +                       }
431 +               }
432 +       }
433 +}
434 +
435 +static void jbd_stats_proc_exit(journal_t *journal)
436 +{
437 +       char name[64];
438 +
439 +       snprintf(name, sizeof(name) - 1, "%s", bdevname(journal->j_dev, name));
440 +       remove_proc_entry("info", journal->j_proc_entry);
441 +       remove_proc_entry("history", journal->j_proc_entry);
442 +       remove_proc_entry(name, proc_jbd_stats);
443 +}
444 +
445 +static void journal_init_stats(journal_t *journal)
446 +{
447 +       int size;
448 +
449 +       if (proc_jbd_stats == NULL)
450 +               return;
451 +
452 +       journal->j_history_max = 100;
453 +       size = sizeof(struct transaction_stats_s) * journal->j_history_max;
454 +       journal->j_history = kmalloc(size, GFP_KERNEL);
455 +       if (journal->j_history == NULL) {
456 +               journal->j_history_max = 0;
457 +               return;
458 +       }
459 +       memset(journal->j_history, 0, size);
460 +       spin_lock_init(&journal->j_history_lock);
461 +}
462 +
463  /*
464   * Management for journal control blocks: functions to create and
465   * destroy journal_t structures, and to initialise and read existing
466 @@ -681,6 +976,9 @@ static journal_t * journal_init_common (
467                 kfree(journal);
468                 goto fail;
469         }
470 +
471 +       journal_init_stats(journal);
472 +
473         return journal;
474  fail:
475         return NULL;
476 @@ -724,6 +1022,7 @@ journal_t * journal_init_dev(struct bloc
477         journal->j_blk_offset = start;
478         journal->j_maxlen = len;
479         journal->j_blocksize = blocksize;
480 +       jbd_stats_proc_init(journal);
481  
482         bh = __getblk(journal->j_dev, start, journal->j_blocksize);
483         J_ASSERT(bh != NULL);
484 @@ -773,6 +1072,7 @@ journal_t * journal_init_inode (struct i
485  
486         journal->j_maxlen = inode->i_size >> inode->i_sb->s_blocksize_bits;
487         journal->j_blocksize = inode->i_sb->s_blocksize;
488 +       jbd_stats_proc_init(journal);
489  
490         /* journal descriptor can store up to n blocks -bzzz */
491         n = journal->j_blocksize / sizeof(journal_block_tag_t);
492 @@ -1161,6 +1461,8 @@ void journal_destroy(journal_t *journal)
493                 brelse(journal->j_sb_buffer);
494         }
495  
496 +       if (journal->j_proc_entry)
497 +               jbd_stats_proc_exit(journal);
498         if (journal->j_inode)
499                 iput(journal->j_inode);
500         if (journal->j_revoke)
501 @@ -2027,6 +2329,28 @@ static void __exit remove_jbd_proc_entry
502  
503  #endif
504  
505 +#if defined(CONFIG_PROC_FS)
506 +
507 +#define JBD_STATS_PROC_NAME "fs/jbd"
508 +
509 +static void __init create_jbd_stats_proc_entry(void)
510 +{
511 +       proc_jbd_stats = proc_mkdir(JBD_STATS_PROC_NAME, NULL);
512 +}
513 +
514 +static void __exit remove_jbd_stats_proc_entry(void)
515 +{
516 +       if (proc_jbd_stats)
517 +               remove_proc_entry(JBD_STATS_PROC_NAME, NULL);
518 +}
519 +
520 +#else
521 +
522 +#define create_jbd_stats_proc_entry() do {} while (0)
523 +#define remove_jbd_stats_proc_entry() do {} while (0)
524 +
525 +#endif
526 +
527  kmem_cache_t *jbd_handle_cache;
528  
529  static int __init journal_init_handle_cache(void)
530 @@ -2090,6 +2414,7 @@ static int __init journal_init(void)
531         if (ret != 0)
532                 journal_destroy_caches();
533         create_jbd_proc_entry();
534 +       create_jbd_stats_proc_entry();
535         return ret;
536  }
537  
538 @@ -2101,6 +2426,7 @@ static void __exit journal_exit(void)
539                 printk(KERN_EMERG "JBD: leaked %d journal_heads!\n", n);
540  #endif
541         remove_jbd_proc_entry();
542 +       remove_jbd_stats_proc_entry();
543         journal_destroy_caches();
544  }
545  
546 Index: linux-2.6.18-8.1.8/fs/jbd/checkpoint.c
547 ===================================================================
548 --- linux-2.6.18-8.1.8.orig/fs/jbd/checkpoint.c 2007-08-28 22:22:10.000000000 +0200
549 +++ linux-2.6.18-8.1.8/fs/jbd/checkpoint.c      2007-08-28 22:23:23.000000000 +0200
550 @@ -231,7 +231,7 @@ __flush_batch(journal_t *journal, struct
551   * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it
552   */
553  static int __process_buffer(journal_t *journal, struct journal_head *jh,
554 -                       struct buffer_head **bhs, int *batch_count)
555 +                       struct buffer_head **bhs, int *batch_count, transaction_t *transaction)
556  {
557         struct buffer_head *bh = jh2bh(jh);
558         int ret = 0;
559 @@ -249,6 +249,7 @@ static int __process_buffer(journal_t *j
560                 transaction_t *t = jh->b_transaction;
561                 tid_t tid = t->t_tid;
562  
563 +               transaction->t_chp_stats.cs_forced_to_close++;
564                 spin_unlock(&journal->j_list_lock);
565                 jbd_unlock_bh_state(bh);
566                 log_start_commit(journal, tid);
567 @@ -278,6 +279,7 @@ static int __process_buffer(journal_t *j
568                 bhs[*batch_count] = bh;
569                 __buffer_relink_io(jh);
570                 jbd_unlock_bh_state(bh);
571 +               transaction->t_chp_stats.cs_written++;
572                 (*batch_count)++;
573                 if (*batch_count == NR_BATCH) {
574                         spin_unlock(&journal->j_list_lock);
575 @@ -321,6 +323,8 @@ int log_do_checkpoint(journal_t *journal
576         if (!journal->j_checkpoint_transactions)
577                 goto out;
578         transaction = journal->j_checkpoint_transactions;
579 +       if (transaction->t_chp_stats.cs_chp_time == 0)
580 +               transaction->t_chp_stats.cs_chp_time = CURRENT_MSECS;
581         this_tid = transaction->t_tid;
582  restart:
583         /*
584 @@ -345,7 +349,8 @@ restart:
585                                 retry = 1;
586                                 break;
587                         }
588 -                       retry = __process_buffer(journal, jh, bhs,&batch_count);
589 +                       retry = __process_buffer(journal, jh, bhs,&batch_count,
590 +                                                transaction);
591                         if (retry < 0 && !result)
592                                 result = retry;
593                         if (!retry && lock_need_resched(&journal->j_list_lock)){
594 @@ -667,6 +672,8 @@ void __journal_insert_checkpoint(struct 
595  
596  void __journal_drop_transaction(journal_t *journal, transaction_t *transaction)
597  {
598 +       struct transaction_stats_s stats;
599 +
600         assert_spin_locked(&journal->j_list_lock);
601         if (transaction->t_cpnext) {
602                 transaction->t_cpnext->t_cpprev = transaction->t_cpprev;
603 @@ -693,5 +700,25 @@ void __journal_drop_transaction(journal_
604         J_ASSERT(journal->j_running_transaction != transaction);
605  
606         jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid);
607 +
608 +       /*
609 +        * File the transaction for history
610 +        */
611 +       if (transaction->t_chp_stats.cs_written != 0 ||
612 +                       transaction->t_chp_stats.cs_chp_time != 0) {
613 +               stats.ts_type = JBD_STATS_CHECKPOINT;
614 +               stats.ts_tid = transaction->t_tid;
615 +               stats.u.chp = transaction->t_chp_stats;
616 +               if (stats.ts_chp_time)
617 +                       stats.ts_chp_time =
618 +                               jbd_time_diff(stats.ts_chp_time, CURRENT_MSECS);
619 +               spin_lock(&journal->j_history_lock);
620 +               memcpy(journal->j_history + journal->j_history_cur, &stats,
621 +                               sizeof(stats));
622 +               if (++journal->j_history_cur == journal->j_history_max)
623 +                       journal->j_history_cur = 0;
624 +               spin_unlock(&journal->j_history_lock);
625 +       }
626 +
627         kfree(transaction);
628  }
629 Index: linux-2.6.18-8.1.8/fs/jbd/commit.c
630 ===================================================================
631 --- linux-2.6.18-8.1.8.orig/fs/jbd/commit.c     2007-08-28 22:22:10.000000000 +0200
632 +++ linux-2.6.18-8.1.8/fs/jbd/commit.c  2007-08-28 22:22:29.000000000 +0200
633 @@ -13,6 +13,7 @@
634   * part of the ext2fs journaling system.
635   */
636  
637 +#include <linux/jiffies.h>
638  #include <linux/time.h>
639  #include <linux/fs.h>
640  #include <linux/jbd.h>
641 @@ -23,6 +24,7 @@
642  #include <linux/smp_lock.h>
643  #include <linux/crc32.h>
644  
645 +
646  /*
647   * Default IO end handler for temporary BJ_IO buffer_heads.
648   */
649 @@ -355,6 +357,7 @@ write_out_data:
650   */
651  void journal_commit_transaction(journal_t *journal)
652  {
653 +       struct transaction_stats_s stats;
654         transaction_t *commit_transaction;
655         struct journal_head *jh, *new_jh, *descriptor;
656         struct buffer_head **wbuf = journal->j_wbuf;
657 @@ -403,6 +406,11 @@ void journal_commit_transaction(journal_
658         spin_lock(&journal->j_state_lock);
659         commit_transaction->t_state = T_LOCKED;
660  
661 +       stats.ts_wait = commit_transaction->t_max_wait;
662 +       stats.ts_locked = CURRENT_MSECS;
663 +       stats.ts_running = jbd_time_diff(commit_transaction->t_start,
664 +                                               stats.ts_locked);
665 +
666         spin_lock(&commit_transaction->t_handle_lock);
667         while (commit_transaction->t_updates) {
668                 DEFINE_WAIT(wait);
669 @@ -473,6 +481,9 @@ void journal_commit_transaction(journal_
670          */
671         journal_switch_revoke_table(journal);
672  
673 +       stats.ts_flushing = CURRENT_MSECS;
674 +       stats.ts_locked = jbd_time_diff(stats.ts_locked, stats.ts_flushing);
675 +
676         commit_transaction->t_state = T_FLUSH;
677         journal->j_committing_transaction = commit_transaction;
678         journal->j_running_transaction = NULL;
679 @@ -540,6 +551,11 @@ void journal_commit_transaction(journal_
680          */
681         commit_transaction->t_state = T_COMMIT;
682  
683 +       stats.ts_logging = CURRENT_MSECS;
684 +       stats.ts_flushing = jbd_time_diff(stats.ts_flushing, stats.ts_logging);
685 +       stats.ts_blocks = commit_transaction->t_outstanding_credits;
686 +       stats.ts_blocks_logged = 0;
687 +
688         descriptor = NULL;
689         bufs = 0;
690         while (commit_transaction->t_buffers) {
691 @@ -698,6 +714,7 @@ start_journal_io:
692                                 submit_bh(WRITE, bh);
693                         }
694                         cond_resched();
695 +                       stats.ts_blocks_logged += bufs;
696  
697                         /* Force a new descriptor to be generated next
698                             time round the loop. */
699 @@ -915,6 +932,7 @@ restart_loop:
700                 cp_transaction = jh->b_cp_transaction;
701                 if (cp_transaction) {
702                         JBUFFER_TRACE(jh, "remove from old cp transaction");
703 +                       cp_transaction->t_chp_stats.cs_dropped++;
704                         __journal_remove_checkpoint(jh);
705                 }
706  
707 @@ -989,6 +1007,36 @@ restart_loop:
708  
709         J_ASSERT(commit_transaction->t_state == T_COMMIT);
710  
711 +       commit_transaction->t_start = CURRENT_MSECS;
712 +       stats.ts_logging = jbd_time_diff(stats.ts_logging,
713 +                                        commit_transaction->t_start);
714 +
715 +       /*
716 +        * File the transaction for history
717 +        */
718 +       stats.ts_type = JBD_STATS_RUN;
719 +       stats.ts_tid = commit_transaction->t_tid;
720 +       stats.ts_handle_count = commit_transaction->t_handle_count;
721 +       spin_lock(&journal->j_history_lock);
722 +       memcpy(journal->j_history + journal->j_history_cur, &stats,
723 +                       sizeof(stats));
724 +       if (++journal->j_history_cur == journal->j_history_max)
725 +               journal->j_history_cur = 0;
726 +
727 +       /*
728 +        * Calculate overall stats
729 +        */
730 +       journal->j_stats.ts_tid++;
731 +       journal->j_stats.ts_wait += stats.ts_wait;
732 +       journal->j_stats.ts_running += stats.ts_running;
733 +       journal->j_stats.ts_locked += stats.ts_locked;
734 +       journal->j_stats.ts_flushing += stats.ts_flushing;
735 +       journal->j_stats.ts_logging += stats.ts_logging;
736 +       journal->j_stats.ts_handle_count += stats.ts_handle_count;
737 +       journal->j_stats.ts_blocks += stats.ts_blocks;
738 +       journal->j_stats.ts_blocks_logged += stats.ts_blocks_logged;
739 +       spin_unlock(&journal->j_history_lock);
740 +
741         commit_transaction->t_state = T_FINISHED;
742         J_ASSERT(commit_transaction == journal->j_committing_transaction);
743         journal->j_commit_sequence = commit_transaction->t_tid;
744