aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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