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
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 bed708c..ffc7c19 100644
23 @@ -983,6 +983,9 @@ struct ext4_inode_info {
27 +#define EXT4_MOUNT2_AKPM_LOCK_HACK 0x80000000 /* akpm lock hack */
30 #define clear_opt(sb, opt) EXT4_SB(sb)->s_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 f71838f..54a9f50 100644
37 @@ -1130,6 +1130,7 @@ enum {
38 Opt_dioread_nolock, Opt_dioread_lock,
39 Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable,
44 static const match_table_t tokens = {
45 @@ -1185,6 +1186,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 @@ -1439,6 +1441,9 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
55 sb->s_flags |= MS_I_VERSION;
57 + case Opt_akpm_lock_hack:
58 + set_opt2(sb, AKPM_LOCK_HACK);
62 for (m = ext4_mount_opts; m->token != Opt_err; m++)
63 @@ -1758,6 +1763,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 @@ -4173,6 +4180,10 @@ static void ext4_init_journal_params(struct super_block *sb, journal_t *journal)
73 journal->j_flags |= JBD2_ABORT_ON_SYNCDATA_ERR;
75 journal->j_flags &= ~JBD2_ABORT_ON_SYNCDATA_ERR;
76 + if (test_opt2(sb, AKPM_LOCK_HACK))
77 + journal->j_flags |= JBD2_LOCK_HACK;
79 + journal->j_flags &= ~JBD2_LOCK_HACK;
80 write_unlock(&journal->j_state_lock);
83 diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
84 index c0035b2..e6bcc8d 100644
85 --- a/fs/jbd2/transaction.c
86 +++ b/fs/jbd2/transaction.c
87 @@ -642,6 +642,7 @@ do_get_write_access(handle_t *handle, struct journal_head *jh,
88 char *frozen_buffer = NULL;
90 unsigned long start_lock, time_lock;
93 if (is_handle_aborted(handle))
95 @@ -658,7 +659,13 @@ repeat:
96 /* @@@ Need to check for errors here at some point. */
100 + if (journal->j_flags & JBD2_LOCK_HACK) {
101 + if (trylock_buffer(bh))
102 + locked = 1; /* lolz */
107 jbd_lock_bh_state(bh);
109 /* If it takes too long to lock the buffer, trace it */
110 @@ -705,7 +712,8 @@ repeat:
111 set_buffer_jbddirty(bh);
119 if (is_handle_aborted(handle)) {
120 diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
121 index 6e051f4..1bf0a51 100644
122 --- a/include/linux/jbd2.h
123 +++ b/include/linux/jbd2.h
124 @@ -977,6 +977,7 @@ struct journal_s
125 #define JBD2_ABORT_ON_SYNCDATA_ERR 0x040 /* Abort the journal on file
126 * data write error in ordered
128 +#define JBD2_LOCK_HACK 0x080 /* akpm's locking hack */
131 * Function declarations for the journaling transaction and buffer