Add cc: stable@vger.kernel.org tags
[ext4-patch-queue.git] / akpm-jbd2-locking-fix
blobadea7d949f1127f4e6edbe9584b2c092b4b9fb50
1 ext4: akpm's locking hack to fix locking delays
3 This is a port of the following patch from Andrew Morton to ext4:
5         http://lkml.org/lkml/2008/10/3/22
7 This fixes a major contention problem in do_get_write_access() when a
8 buffer is modified in both the current and committing transaction.
10 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
11 Cc: akpm@linux-foundation.org
12 ---
13  fs/ext4/ext4.h        |  3 +++
14  fs/ext4/super.c       | 11 +++++++++++
15  fs/jbd2/transaction.c | 12 ++++++++++--
16  include/linux/jbd2.h  |  1 +
17  4 files changed, 25 insertions(+), 2 deletions(-)
19 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
20 index 4a17e88..d19ef59 100644
21 --- a/fs/ext4/ext4.h
22 +++ b/fs/ext4/ext4.h
23 @@ -977,6 +977,9 @@ struct ext4_inode_info {
24                                                       size of blocksize * 8
25                                                       blocks */
27 +#define EXT4_MOUNT2_AKPM_LOCK_HACK     0x80000000 /* akpm lock hack */
30  #define clear_opt(sb, opt)             EXT4_SB(sb)->s_mount_opt &= \
31                                                 ~EXT4_MOUNT_##opt
32  #define set_opt(sb, opt)               EXT4_SB(sb)->s_mount_opt |= \
33 diff --git a/fs/ext4/super.c b/fs/ext4/super.c
34 index 79de0b1..86a80d2 100644
35 --- a/fs/ext4/super.c
36 +++ b/fs/ext4/super.c
37 @@ -1151,6 +1151,7 @@ enum {
38         Opt_dioread_nolock, Opt_dioread_lock,
39         Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable,
40         Opt_max_dir_size_kb,
41 +       Opt_akpm_lock_hack,
42  };
44  static const match_table_t tokens = {
45 @@ -1206,6 +1207,7 @@ static const match_table_t tokens = {
46         {Opt_nobarrier, "nobarrier"},
47         {Opt_i_version, "i_version"},
48         {Opt_stripe, "stripe=%u"},
49 +       {Opt_akpm_lock_hack, "akpm_lock_hack"},
50         {Opt_delalloc, "delalloc"},
51         {Opt_nodelalloc, "nodelalloc"},
52         {Opt_removed, "mblk_io_submit"},
53 @@ -1460,6 +1462,9 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
54         case Opt_i_version:
55                 sb->s_flags |= MS_I_VERSION;
56                 return 1;
57 +       case Opt_akpm_lock_hack:
58 +               set_opt2(sb, AKPM_LOCK_HACK);
59 +               return 1;
60         }
62         for (m = ext4_mount_opts; m->token != Opt_err; m++)
63 @@ -1779,6 +1784,8 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
64                 SEQ_OPTS_PRINT("min_batch_time=%u", sbi->s_min_batch_time);
65         if (nodefs || sbi->s_max_batch_time != EXT4_DEF_MAX_BATCH_TIME)
66                 SEQ_OPTS_PRINT("max_batch_time=%u", sbi->s_max_batch_time);
67 +       if (test_opt2(sb, AKPM_LOCK_HACK))
68 +               seq_puts(seq, ",akpm_lock_hack");
69         if (sb->s_flags & MS_I_VERSION)
70                 SEQ_OPTS_PUTS("i_version");
71         if (nodefs || sbi->s_stripe)
72 @@ -4299,6 +4306,10 @@ static void ext4_init_journal_params(struct super_block *sb, journal_t *journal)
73                 journal->j_flags |= JBD2_ABORT_ON_SYNCDATA_ERR;
74         else
75                 journal->j_flags &= ~JBD2_ABORT_ON_SYNCDATA_ERR;
76 +       if (test_opt2(sb, AKPM_LOCK_HACK))
77 +               journal->j_flags |= JBD2_LOCK_HACK;
78 +       else
79 +               journal->j_flags &= ~JBD2_LOCK_HACK;
80         write_unlock(&journal->j_state_lock);
81  }
83 diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
84 index e1c0b4a..6d6b6bc 100644
85 --- a/fs/jbd2/transaction.c
86 +++ b/fs/jbd2/transaction.c
87 @@ -788,6 +788,7 @@ do_get_write_access(handle_t *handle, struct journal_head *jh,
88         char *frozen_buffer = NULL;
89         int need_copy = 0;
90         unsigned long start_lock, time_lock;
91 +       int locked = 0;
93         WARN_ON(!transaction);
94         if (is_handle_aborted(handle))
95 @@ -803,7 +804,13 @@ repeat:
96         /* @@@ Need to check for errors here at some point. */
98         start_lock = jiffies;
99 -       lock_buffer(bh);
100 +       if (journal->j_flags & JBD2_LOCK_HACK) {
101 +               if (trylock_buffer(bh))
102 +                       locked = 1;     /* lolz */
103 +       } else {
104 +               lock_buffer(bh);
105 +               locked = 1;
106 +       }
107         jbd_lock_bh_state(bh);
109         /* If it takes too long to lock the buffer, trace it */
110 @@ -850,7 +857,8 @@ repeat:
111                 set_buffer_jbddirty(bh);
112         }
114 -       unlock_buffer(bh);
115 +       if (locked)
116 +               unlock_buffer(bh);
118         error = -EROFS;
119         if (is_handle_aborted(handle)) {
120 diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
121 index d5b50a1..6f850b4 100644
122 --- a/include/linux/jbd2.h
123 +++ b/include/linux/jbd2.h
124 @@ -996,6 +996,7 @@ struct journal_s
125  #define JBD2_ABORT_ON_SYNCDATA_ERR     0x040   /* Abort the journal on file
126                                                  * data write error in ordered
127                                                  * mode */
128 +#define JBD2_LOCK_HACK 0x080   /* akpm's locking hack */
130  /*
131   * Function declarations for the journaling transaction and buffer