diff options
-rw-r--r-- | fs/ext4/inode.c | 64 | ||||
-rw-r--r-- | fs/ext4/super.c | 10 | ||||
-rw-r--r-- | include/trace/events/ext4.h | 30 |
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 | ||
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 | |||
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 | ||
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 | |||
76 | TRACE_EVENT(ext4_free_inode, | 106 | TRACE_EVENT(ext4_free_inode, |
77 | TP_PROTO(struct inode *inode), | 107 | TP_PROTO(struct inode *inode), |
78 | 108 | ||