Whamcloud - gitweb
b=18649 set wait_recovery_complete() MAX value to max recovery time estimated
[fs/lustre-release.git] / lustre / kernel_patches / patches / jbd-stats-2.6-sles10.patch
1 Index: linux-2.6.16.46-0.14/include/linux/jbd.h
2 ===================================================================
3 --- linux-2.6.16.46-0.14.orig/include/linux/jbd.h
4 +++ linux-2.6.16.46-0.14/include/linux/jbd.h
5 @@ -422,6 +422,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 @@ -553,6 +563,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 @@ -592,6 +617,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 @@ -845,6 +921,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.16.46-0.14/fs/jbd/transaction.c
120 ===================================================================
121 --- linux-2.6.16.46-0.14.orig/fs/jbd/transaction.c
122 +++ linux-2.6.16.46-0.14/fs/jbd/transaction.c
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.16.46-0.14/fs/jbd/journal.c
154 ===================================================================
155 --- linux-2.6.16.46-0.14.orig/fs/jbd/journal.c
156 +++ linux-2.6.16.46-0.14/fs/jbd/journal.c
157 @@ -36,6 +36,7 @@
158  #include <asm/uaccess.h>
159  #include <asm/page.h>
160  #include <linux/proc_fs.h>
161 +#include <linux/seq_file.h>
162  
163  EXPORT_SYMBOL(journal_start);
164  EXPORT_SYMBOL(journal_restart);
165 @@ -637,6 +638,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 @@ -679,6 +974,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 @@ -722,6 +1020,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 @@ -771,6 +1070,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 @@ -1152,6 +1452,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 @@ -1920,6 +2222,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 @@ -1982,6 +2306,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 @@ -1993,6 +2318,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.16.46-0.14/fs/jbd/checkpoint.c
547 ===================================================================
548 --- linux-2.6.16.46-0.14.orig/fs/jbd/checkpoint.c
549 +++ linux-2.6.16.46-0.14/fs/jbd/checkpoint.c
550 @@ -166,6 +166,7 @@ static int __cleanup_transaction(journal
551                         transaction_t *t = jh->b_transaction;
552                         tid_t tid = t->t_tid;
553  
554 +                       transaction->t_chp_stats.cs_forced_to_close++;
555                         spin_unlock(&journal->j_list_lock);
556                         jbd_unlock_bh_state(bh);
557                         log_start_commit(journal, tid);
558 @@ -226,7 +227,7 @@ __flush_batch(journal_t *journal, struct
559   */
560  static int __flush_buffer(journal_t *journal, struct journal_head *jh,
561                         struct buffer_head **bhs, int *batch_count,
562 -                       int *drop_count)
563 +                       int *drop_count, transaction_t *transaction)
564  {
565         struct buffer_head *bh = jh2bh(jh);
566         int ret = 0;
567 @@ -247,6 +248,7 @@ static int __flush_buffer(journal_t *jou
568                 set_buffer_jwrite(bh);
569                 bhs[*batch_count] = bh;
570                 jbd_unlock_bh_state(bh);
571 +               transaction->t_chp_stats.cs_written++;
572                 (*batch_count)++;
573                 if (*batch_count == NR_BATCH) {
574                         __flush_batch(journal, bhs, batch_count);
575 @@ -315,6 +317,8 @@ int log_do_checkpoint(journal_t *journal
576                 tid_t this_tid;
577  
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                 jh = transaction->t_checkpoint_list;
583                 last_jh = jh->b_cpprev;
584 @@ -331,7 +335,8 @@ int log_do_checkpoint(journal_t *journal
585                                 retry = 1;
586                                 break;
587                         }
588 -                       retry = __flush_buffer(journal, jh, bhs, &batch_count, &drop_count);
589 +                       retry = __flush_buffer(journal, jh, bhs, &batch_count,
590 +                                               &drop_count, transaction);
591                         if (cond_resched_lock(&journal->j_list_lock)) {
592                                 retry = 1;
593                                 break;
594 @@ -609,6 +614,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 @@ -634,5 +641,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.16.46-0.14/fs/jbd/commit.c
630 ===================================================================
631 --- linux-2.6.16.46-0.14.orig/fs/jbd/commit.c
632 +++ linux-2.6.16.46-0.14/fs/jbd/commit.c
633 @@ -21,6 +21,7 @@
634  #include <linux/mm.h>
635  #include <linux/pagemap.h>
636  #include <linux/smp_lock.h>
637 +#include <linux/jiffies.h>
638  
639  /*
640   * Default IO end handler for temporary BJ_IO buffer_heads.
641 @@ -168,6 +169,7 @@ static int journal_write_commit_record(j
642   */
643  void journal_commit_transaction(journal_t *journal)
644  {
645 +       struct transaction_stats_s stats;
646         transaction_t *commit_transaction;
647         struct journal_head *jh, *new_jh, *descriptor;
648         struct buffer_head **wbuf = journal->j_wbuf;
649 @@ -214,6 +216,11 @@ void journal_commit_transaction(journal_
650         spin_lock(&journal->j_state_lock);
651         commit_transaction->t_state = T_LOCKED;
652  
653 +       stats.ts_wait = commit_transaction->t_max_wait;
654 +       stats.ts_locked = CURRENT_MSECS;
655 +       stats.ts_running = jbd_time_diff(commit_transaction->t_start,
656 +                                               stats.ts_locked);
657 +
658         spin_lock(&commit_transaction->t_handle_lock);
659         while (commit_transaction->t_updates) {
660                 DEFINE_WAIT(wait);
661 @@ -284,6 +291,9 @@ void journal_commit_transaction(journal_
662          */
663         journal_switch_revoke_table(journal);
664  
665 +       stats.ts_flushing = CURRENT_MSECS;
666 +       stats.ts_locked = jbd_time_diff(stats.ts_locked, stats.ts_flushing);
667 +
668         commit_transaction->t_state = T_FLUSH;
669         journal->j_committing_transaction = commit_transaction;
670         journal->j_running_transaction = NULL;
671 @@ -442,6 +452,11 @@ write_out_data:
672          */
673         commit_transaction->t_state = T_COMMIT;
674  
675 +       stats.ts_logging = CURRENT_MSECS;
676 +       stats.ts_flushing = jbd_time_diff(stats.ts_flushing, stats.ts_logging);
677 +       stats.ts_blocks = commit_transaction->t_outstanding_credits;
678 +       stats.ts_blocks_logged = 0;
679 +
680         descriptor = NULL;
681         bufs = 0;
682         while (commit_transaction->t_buffers) {
683 @@ -590,6 +605,7 @@ start_journal_io:
684                                 submit_bh(WRITE, bh);
685                         }
686                         cond_resched();
687 +                       stats.ts_blocks_logged += bufs;
688  
689                         /* Force a new descriptor to be generated next
690                             time round the loop. */
691 @@ -784,6 +800,7 @@ restart_loop:
692                 cp_transaction = jh->b_cp_transaction;
693                 if (cp_transaction) {
694                         JBUFFER_TRACE(jh, "remove from old cp transaction");
695 +                       cp_transaction->t_chp_stats.cs_dropped++;
696                         __journal_remove_checkpoint(jh);
697                 }
698  
699 @@ -858,6 +875,36 @@ restart_loop:
700  
701         J_ASSERT(commit_transaction->t_state == T_COMMIT);
702  
703 +       commit_transaction->t_start = CURRENT_MSECS;
704 +       stats.ts_logging = jbd_time_diff(stats.ts_logging,
705 +                                        commit_transaction->t_start);
706 +
707 +       /*
708 +        * File the transaction for history
709 +        */
710 +       stats.ts_type = JBD_STATS_RUN;
711 +       stats.ts_tid = commit_transaction->t_tid;
712 +       stats.ts_handle_count = commit_transaction->t_handle_count;
713 +       spin_lock(&journal->j_history_lock);
714 +       memcpy(journal->j_history + journal->j_history_cur, &stats,
715 +                       sizeof(stats));
716 +       if (++journal->j_history_cur == journal->j_history_max)
717 +               journal->j_history_cur = 0;
718 +
719 +       /*
720 +        * Calculate overall stats
721 +        */
722 +       journal->j_stats.ts_tid++;
723 +       journal->j_stats.ts_wait += stats.ts_wait;
724 +       journal->j_stats.ts_running += stats.ts_running;
725 +       journal->j_stats.ts_locked += stats.ts_locked;
726 +       journal->j_stats.ts_flushing += stats.ts_flushing;
727 +       journal->j_stats.ts_logging += stats.ts_logging;
728 +       journal->j_stats.ts_handle_count += stats.ts_handle_count;
729 +       journal->j_stats.ts_blocks += stats.ts_blocks;
730 +       journal->j_stats.ts_blocks_logged += stats.ts_blocks_logged;
731 +       spin_unlock(&journal->j_history_lock);
732 +
733         commit_transaction->t_state = T_FINISHED;
734         J_ASSERT(commit_transaction == journal->j_committing_transaction);
735         journal->j_commit_sequence = commit_transaction->t_tid;