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 b7dbaf1..c5b26f7 100644
23 @@ -1006,6 +1006,9 @@ struct ext4_inode_info {
24 #define EXT4_MOUNT2_HURD_COMPAT 0x00000004 /* Support HURD-castrated
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 7b3a41c..ccab545 100644
37 @@ -1135,6 +1135,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, Opt_nojournal_checksum,
44 static const match_table_t tokens = {
45 @@ -1193,6 +1194,7 @@ static const match_table_t tokens = {
46 {Opt_i_version, "i_version"},
48 {Opt_stripe, "stripe=%u"},
49 + {Opt_akpm_lock_hack, "akpm_lock_hack"},
50 {Opt_delalloc, "delalloc"},
51 {Opt_lazytime, "lazytime"},
52 {Opt_nolazytime, "nolazytime"},
53 @@ -1460,6 +1462,9 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
55 sb->s_flags &= ~MS_LAZYTIME;
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 @@ -1813,6 +1818,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 @@ -4442,6 +4449,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 93ffee2..4ba2b76 100644
85 --- a/fs/jbd2/transaction.c
86 +++ b/fs/jbd2/transaction.c
87 @@ -784,6 +784,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 WARN_ON(!transaction);
94 if (is_handle_aborted(handle))
95 @@ -799,7 +800,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 @@ -846,7 +853,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 20e7f78..0f17d76 100644
122 --- a/include/linux/jbd2.h
123 +++ b/include/linux/jbd2.h
124 @@ -1007,6 +1007,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