Skip to content

Commit a26f499

Browse files
tytsoAl Viro
authored andcommitted
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 <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent fe032c4 commit a26f499

File tree

3 files changed

+102
-2
lines changed

3 files changed

+102
-2
lines changed

fs/ext4/inode.c

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4139,6 +4139,65 @@ static int ext4_inode_blocks_set(handle_t *handle,
41394139
return 0;
41404140
}
41414141

4142+
struct other_inode {
4143+
unsigned long orig_ino;
4144+
struct ext4_inode *raw_inode;
4145+
};
4146+
4147+
static 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+
*/
4183+
static 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+
41424201
/*
41434202
* Post the struct inode info into an on-disk inode location in the
41444203
* buffer-cache. This gobbles the caller's reference to the
@@ -4248,10 +4307,11 @@ static int ext4_do_update_inode(handle_t *handle,
42484307
cpu_to_le16(ei->i_extra_isize);
42494308
}
42504309
}
4251-
42524310
ext4_inode_csum_set(inode, raw_inode, ei);
4253-
42544311
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);
42554315

42564316
BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
42574317
rc = ext4_handle_dirty_metadata(handle, NULL, bh);

fs/ext4/super.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,6 +1139,7 @@ enum {
11391139
Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err,
11401140
Opt_usrquota, Opt_grpquota, Opt_i_version,
11411141
Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_mblk_io_submit,
1142+
Opt_lazytime, Opt_nolazytime,
11421143
Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity,
11431144
Opt_inode_readahead_blks, Opt_journal_ioprio,
11441145
Opt_dioread_nolock, Opt_dioread_lock,
@@ -1202,6 +1203,8 @@ static const match_table_t tokens = {
12021203
{Opt_i_version, "i_version"},
12031204
{Opt_stripe, "stripe=%u"},
12041205
{Opt_delalloc, "delalloc"},
1206+
{Opt_lazytime, "lazytime"},
1207+
{Opt_nolazytime, "nolazytime"},
12051208
{Opt_nodelalloc, "nodelalloc"},
12061209
{Opt_removed, "mblk_io_submit"},
12071210
{Opt_removed, "nomblk_io_submit"},
@@ -1459,6 +1462,12 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
14591462
case Opt_i_version:
14601463
sb->s_flags |= MS_I_VERSION;
14611464
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;
14621471
}
14631472

14641473
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)
50205029
}
50215030
#endif
50225031

5032+
*flags = (*flags & ~MS_LAZYTIME) | (sb->s_flags & MS_LAZYTIME);
50235033
ext4_msg(sb, KERN_INFO, "re-mounted. Opts: %s", orig_data);
50245034
kfree(orig_data);
50255035
return 0;

include/trace/events/ext4.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,36 @@ struct extent_status;
7373
{ FALLOC_FL_ZERO_RANGE, "ZERO_RANGE"})
7474

7575

76+
TRACE_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+
76106
TRACE_EVENT(ext4_free_inode,
77107
TP_PROTO(struct inode *inode),
78108

0 commit comments

Comments
 (0)