aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2015-02-02 00:37:02 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2015-02-05 02:45:00 -0500
commita26f49926da938f47561f386be56a83dd37a496d (patch)
tree00d84a2406137aab5cc4b8ed290f962608558d70
parentfe032c422c5ba562ba9c2d316f55e258e03259c6 (diff)
ext4: add optimization for the lazytime mount option
Add an optimization for the MS_LAZYTIME mount option so that we will opportunistically write out any inodes with the I_DIRTY_TIME flag set in a particular inode table block when we need to update some inode in that inode table block anyway. Also add some temporary code so that we can set the lazytime mount option without needing a modified /sbin/mount program which can set MS_LAZYTIME. We can eventually make this go away once util-linux has added support. Google-Bug-Id: 18297052 Signed-off-by: Theodore Ts'o <tytso@mit.edu> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/ext4/inode.c64
-rw-r--r--fs/ext4/super.c10
-rw-r--r--include/trace/events/ext4.h30
3 files changed, 102 insertions, 2 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 628df5ba44a6..9193ea130dcb 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4139,6 +4139,65 @@ static int ext4_inode_blocks_set(handle_t *handle,
4139 return 0; 4139 return 0;
4140} 4140}
4141 4141
4142struct other_inode {
4143 unsigned long orig_ino;
4144 struct ext4_inode *raw_inode;
4145};
4146
4147static int other_inode_match(struct inode * inode, unsigned long ino,
4148 void *data)
4149{
4150 struct other_inode *oi = (struct other_inode *) data;
4151
4152 if ((inode->i_ino != ino) ||
4153 (inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW |
4154 I_DIRTY_SYNC | I_DIRTY_DATASYNC)) ||
4155 ((inode->i_state & I_DIRTY_TIME) == 0))
4156 return 0;
4157 spin_lock(&inode->i_lock);
4158 if (((inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW |
4159 I_DIRTY_SYNC | I_DIRTY_DATASYNC)) == 0) &&
4160 (inode->i_state & I_DIRTY_TIME)) {
4161 struct ext4_inode_info *ei = EXT4_I(inode);
4162
4163 inode->i_state &= ~(I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED);
4164 spin_unlock(&inode->i_lock);
4165
4166 spin_lock(&ei->i_raw_lock);
4167 EXT4_INODE_SET_XTIME(i_ctime, inode, oi->raw_inode);
4168 EXT4_INODE_SET_XTIME(i_mtime, inode, oi->raw_inode);
4169 EXT4_INODE_SET_XTIME(i_atime, inode, oi->raw_inode);
4170 ext4_inode_csum_set(inode, oi->raw_inode, ei);
4171 spin_unlock(&ei->i_raw_lock);
4172 trace_ext4_other_inode_update_time(inode, oi->orig_ino);
4173 return -1;
4174 }
4175 spin_unlock(&inode->i_lock);
4176 return -1;
4177}
4178
4179/*
4180 * Opportunistically update the other time fields for other inodes in
4181 * the same inode table block.
4182 */
4183static void ext4_update_other_inodes_time(struct super_block *sb,
4184 unsigned long orig_ino, char *buf)
4185{
4186 struct other_inode oi;
4187 unsigned long ino;
4188 int i, inodes_per_block = EXT4_SB(sb)->s_inodes_per_block;
4189 int inode_size = EXT4_INODE_SIZE(sb);
4190
4191 oi.orig_ino = orig_ino;
4192 ino = orig_ino & ~(inodes_per_block - 1);
4193 for (i = 0; i < inodes_per_block; i++, ino++, buf += inode_size) {
4194 if (ino == orig_ino)
4195 continue;
4196 oi.raw_inode = (struct ext4_inode *) buf;
4197 (void) find_inode_nowait(sb, ino, other_inode_match, &oi);
4198 }
4199}
4200
4142/* 4201/*
4143 * Post the struct inode info into an on-disk inode location in the 4202 * Post the struct inode info into an on-disk inode location in the
4144 * buffer-cache. This gobbles the caller's reference to the 4203 * buffer-cache. This gobbles the caller's reference to the
@@ -4248,10 +4307,11 @@ static int ext4_do_update_inode(handle_t *handle,
4248 cpu_to_le16(ei->i_extra_isize); 4307 cpu_to_le16(ei->i_extra_isize);
4249 } 4308 }
4250 } 4309 }
4251
4252 ext4_inode_csum_set(inode, raw_inode, ei); 4310 ext4_inode_csum_set(inode, raw_inode, ei);
4253
4254 spin_unlock(&ei->i_raw_lock); 4311 spin_unlock(&ei->i_raw_lock);
4312 if (inode->i_sb->s_flags & MS_LAZYTIME)
4313 ext4_update_other_inodes_time(inode->i_sb, inode->i_ino,
4314 bh->b_data);
4255 4315
4256 BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); 4316 BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
4257 rc = ext4_handle_dirty_metadata(handle, NULL, bh); 4317 rc = ext4_handle_dirty_metadata(handle, NULL, bh);
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 74c5f53595fb..362b23c8497a 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1139,6 +1139,7 @@ enum {
1139 Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err, 1139 Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err,
1140 Opt_usrquota, Opt_grpquota, Opt_i_version, 1140 Opt_usrquota, Opt_grpquota, Opt_i_version,
1141 Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_mblk_io_submit, 1141 Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_mblk_io_submit,
1142 Opt_lazytime, Opt_nolazytime,
1142 Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity, 1143 Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity,
1143 Opt_inode_readahead_blks, Opt_journal_ioprio, 1144 Opt_inode_readahead_blks, Opt_journal_ioprio,
1144 Opt_dioread_nolock, Opt_dioread_lock, 1145 Opt_dioread_nolock, Opt_dioread_lock,
@@ -1202,6 +1203,8 @@ static const match_table_t tokens = {
1202 {Opt_i_version, "i_version"}, 1203 {Opt_i_version, "i_version"},
1203 {Opt_stripe, "stripe=%u"}, 1204 {Opt_stripe, "stripe=%u"},
1204 {Opt_delalloc, "delalloc"}, 1205 {Opt_delalloc, "delalloc"},
1206 {Opt_lazytime, "lazytime"},
1207 {Opt_nolazytime, "nolazytime"},
1205 {Opt_nodelalloc, "nodelalloc"}, 1208 {Opt_nodelalloc, "nodelalloc"},
1206 {Opt_removed, "mblk_io_submit"}, 1209 {Opt_removed, "mblk_io_submit"},
1207 {Opt_removed, "nomblk_io_submit"}, 1210 {Opt_removed, "nomblk_io_submit"},
@@ -1459,6 +1462,12 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
1459 case Opt_i_version: 1462 case Opt_i_version:
1460 sb->s_flags |= MS_I_VERSION; 1463 sb->s_flags |= MS_I_VERSION;
1461 return 1; 1464 return 1;
1465 case Opt_lazytime:
1466 sb->s_flags |= MS_LAZYTIME;
1467 return 1;
1468 case Opt_nolazytime:
1469 sb->s_flags &= ~MS_LAZYTIME;
1470 return 1;
1462 } 1471 }
1463 1472
1464 for (m = ext4_mount_opts; m->token != Opt_err; m++) 1473 for (m = ext4_mount_opts; m->token != Opt_err; m++)
@@ -5020,6 +5029,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
5020 } 5029 }
5021#endif 5030#endif
5022 5031
5032 *flags = (*flags & ~MS_LAZYTIME) | (sb->s_flags & MS_LAZYTIME);
5023 ext4_msg(sb, KERN_INFO, "re-mounted. Opts: %s", orig_data); 5033 ext4_msg(sb, KERN_INFO, "re-mounted. Opts: %s", orig_data);
5024 kfree(orig_data); 5034 kfree(orig_data);
5025 return 0; 5035 return 0;
diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h
index 6cfb841fea7c..6e5abd6d38a2 100644
--- a/include/trace/events/ext4.h
+++ b/include/trace/events/ext4.h
@@ -73,6 +73,36 @@ struct extent_status;
73 { FALLOC_FL_ZERO_RANGE, "ZERO_RANGE"}) 73 { FALLOC_FL_ZERO_RANGE, "ZERO_RANGE"})
74 74
75 75
76TRACE_EVENT(ext4_other_inode_update_time,
77 TP_PROTO(struct inode *inode, ino_t orig_ino),
78
79 TP_ARGS(inode, orig_ino),
80
81 TP_STRUCT__entry(
82 __field( dev_t, dev )
83 __field( ino_t, ino )
84 __field( ino_t, orig_ino )
85 __field( uid_t, uid )
86 __field( gid_t, gid )
87 __field( __u16, mode )
88 ),
89
90 TP_fast_assign(
91 __entry->orig_ino = orig_ino;
92 __entry->dev = inode->i_sb->s_dev;
93 __entry->ino = inode->i_ino;
94 __entry->uid = i_uid_read(inode);
95 __entry->gid = i_gid_read(inode);
96 __entry->mode = inode->i_mode;
97 ),
98
99 TP_printk("dev %d,%d orig_ino %lu ino %lu mode 0%o uid %u gid %u",
100 MAJOR(__entry->dev), MINOR(__entry->dev),
101 (unsigned long) __entry->orig_ino,
102 (unsigned long) __entry->ino, __entry->mode,
103 __entry->uid, __entry->gid)
104);
105
76TRACE_EVENT(ext4_free_inode, 106TRACE_EVENT(ext4_free_inode,
77 TP_PROTO(struct inode *inode), 107 TP_PROTO(struct inode *inode),
78 108