From 3bdfab20fc8add21074bfa24c1a6384ae4eda35d Mon Sep 17 00:00:00 2001 From: Andrew Morton <akpm@digeo.com> Date: Sun, 16 Mar 2003 07:22:47 -0800 Subject: [PATCH] [PATCH] Ext2/3 noatime and dirsync fixes Patch from "Theodore Ts'o" <tytso@mit.edu> I recently noticed a bug in ext2/3; newly created inodes which inherit the noatime flag from their containing directory do not respect noatime until the inode is flushed from the inode cache and then re-read later. This is because the code which checks the ext2 no-atime attribute and then sets the S_NOATIME in inode->i_flags is present in ext2_read_inode(), but not in ext2_new_inode(). I fixed this in 2.4, and then found an even worse bug in the 2.5 code; the DIRSYNC flag is completely ignored *except* in the case where a directory is newly created using mkdir and its parent directory has the DIRSYNC flag. S_DIRSYNC doesn't get set in the ext2_new_inode() or the ext2_ioctl() paths (which is used by chattr). This patch centralizes the code which translates the ext2 flags in the raw ext2 inode to the appropriate flag values in inode->i_flags in a single location. This fixes the bug, makes things cleaner, and also removes 30 lines of code and 128 bytes of compiled x86 text in the bargain. --- fs/ext2/ext2.h | 1 + fs/ext2/ialloc.c | 5 +---- fs/ext2/inode.c | 26 ++++++++++++++++++-------- fs/ext2/ioctl.c | 17 +---------------- fs/ext3/ialloc.c | 5 +---- fs/ext3/inode.c | 27 +++++++++++++++++++-------- fs/ext3/ioctl.c | 17 +---------------- include/linux/ext3_fs.h | 1 + 8 files changed, 43 insertions(+), 56 deletions(-) diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 7850dcbe7bf1..610695289845 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -112,6 +112,7 @@ extern int ext2_sync_inode (struct inode *); extern void ext2_discard_prealloc (struct inode *); extern void ext2_truncate (struct inode *); extern int ext2_setattr (struct dentry *, struct iattr *); +extern void ext2_set_inode_flags(struct inode *inode); /* ioctl.c */ extern int ext2_ioctl (struct inode *, struct file *, unsigned int, diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index 345e7495176d..87b2d99f4a7c 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -545,10 +545,7 @@ struct inode * ext2_new_inode(struct inode * dir, int mode) ei->i_prealloc_count = 0; ei->i_dir_start_lookup = 0; ei->i_state = EXT2_STATE_NEW; - if (ei->i_flags & EXT2_SYNC_FL) - inode->i_flags |= S_SYNC; - if (ei->i_flags & EXT2_DIRSYNC_FL) - inode->i_flags |= S_DIRSYNC; + ext2_set_inode_flags(inode); inode->i_generation = EXT2_SB(sb)->s_next_generation++; insert_inode_hash(inode); diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index e47f84e305cd..c2fbefdd3613 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1011,6 +1011,23 @@ static struct ext2_inode *ext2_get_inode(struct super_block *sb, ino_t ino, return ERR_PTR(-EIO); } +void ext2_set_inode_flags(struct inode *inode) +{ + unsigned int flags = EXT2_I(inode)->i_flags; + + inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); + if (flags & EXT2_SYNC_FL) + inode->i_flags |= S_SYNC; + if (flags & EXT2_APPEND_FL) + inode->i_flags |= S_APPEND; + if (flags & EXT2_IMMUTABLE_FL) + inode->i_flags |= S_IMMUTABLE; + if (flags & EXT2_NOATIME_FL) + inode->i_flags |= S_NOATIME; + if (flags & EXT2_DIRSYNC_FL) + inode->i_flags |= S_DIRSYNC; +} + void ext2_read_inode (struct inode * inode) { struct ext2_inode_info *ei = EXT2_I(inode); @@ -1108,14 +1125,7 @@ void ext2_read_inode (struct inode * inode) le32_to_cpu(raw_inode->i_block[0])); } brelse (bh); - if (ei->i_flags & EXT2_SYNC_FL) - inode->i_flags |= S_SYNC; - if (ei->i_flags & EXT2_APPEND_FL) - inode->i_flags |= S_APPEND; - if (ei->i_flags & EXT2_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; - if (ei->i_flags & EXT2_NOATIME_FL) - inode->i_flags |= S_NOATIME; + ext2_set_inode_flags(inode); return; bad_inode: diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c index afff8566f3b6..101055bbf519 100644 --- a/fs/ext2/ioctl.c +++ b/fs/ext2/ioctl.c @@ -58,22 +58,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, flags |= oldflags & ~EXT2_FL_USER_MODIFIABLE; ei->i_flags = flags; - if (flags & EXT2_SYNC_FL) - inode->i_flags |= S_SYNC; - else - inode->i_flags &= ~S_SYNC; - if (flags & EXT2_APPEND_FL) - inode->i_flags |= S_APPEND; - else - inode->i_flags &= ~S_APPEND; - if (flags & EXT2_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; - else - inode->i_flags &= ~S_IMMUTABLE; - if (flags & EXT2_NOATIME_FL) - inode->i_flags |= S_NOATIME; - else - inode->i_flags &= ~S_NOATIME; + ext2_set_inode_flags(inode); inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); return 0; diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index 228fa402af19..155c19c4ac92 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c @@ -568,10 +568,7 @@ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode) #endif ei->i_block_group = group; - if (ei->i_flags & EXT3_SYNC_FL) - inode->i_flags |= S_SYNC; - if (ei->i_flags & EXT3_DIRSYNC_FL) - inode->i_flags |= S_DIRSYNC; + ext3_set_inode_flags(inode); if (IS_DIRSYNC(inode)) handle->h_sync = 1; insert_inode_hash(inode); diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index b37c23fb3d5a..5012c1719ee4 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -2209,6 +2209,24 @@ int ext3_get_inode_loc (struct inode *inode, struct ext3_iloc *iloc) return -EIO; } +void ext3_set_inode_flags(struct inode *inode) +{ + unsigned int flags = EXT3_I(inode)->i_flags; + + inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); + if (flags & EXT3_SYNC_FL) + inode->i_flags |= S_SYNC; + if (flags & EXT3_APPEND_FL) + inode->i_flags |= S_APPEND; + if (flags & EXT3_IMMUTABLE_FL) + inode->i_flags |= S_IMMUTABLE; + if (flags & EXT3_NOATIME_FL) + inode->i_flags |= S_NOATIME; + if (flags & EXT3_DIRSYNC_FL) + inode->i_flags |= S_DIRSYNC; +} + + void ext3_read_inode(struct inode * inode) { struct ext3_iloc iloc; @@ -2320,14 +2338,7 @@ void ext3_read_inode(struct inode * inode) init_special_inode(inode, inode->i_mode, le32_to_cpu(iloc.raw_inode->i_block[0])); } - if (ei->i_flags & EXT3_SYNC_FL) - inode->i_flags |= S_SYNC; - if (ei->i_flags & EXT3_APPEND_FL) - inode->i_flags |= S_APPEND; - if (ei->i_flags & EXT3_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; - if (ei->i_flags & EXT3_NOATIME_FL) - inode->i_flags |= S_NOATIME; + ext3_set_inode_flags(inode); return; bad_inode: diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c index 5d74409cef07..cedf91bde8a2 100644 --- a/fs/ext3/ioctl.c +++ b/fs/ext3/ioctl.c @@ -85,22 +85,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, flags |= oldflags & ~EXT3_FL_USER_MODIFIABLE; ei->i_flags = flags; - if (flags & EXT3_SYNC_FL) - inode->i_flags |= S_SYNC; - else - inode->i_flags &= ~S_SYNC; - if (flags & EXT3_APPEND_FL) - inode->i_flags |= S_APPEND; - else - inode->i_flags &= ~S_APPEND; - if (flags & EXT3_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; - else - inode->i_flags &= ~S_IMMUTABLE; - if (flags & EXT3_NOATIME_FL) - inode->i_flags |= S_NOATIME; - else - inode->i_flags &= ~S_NOATIME; + ext3_set_inode_flags(inode); inode->i_ctime = CURRENT_TIME; err = ext3_mark_iloc_dirty(handle, inode, &iloc); diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index 0612ce8e8274..b3da32479e13 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -730,6 +730,7 @@ extern void ext3_discard_prealloc (struct inode *); extern void ext3_dirty_inode(struct inode *); extern int ext3_change_inode_journal_flag(struct inode *, int); extern void ext3_truncate (struct inode *); +extern void ext3_set_inode_flags(struct inode *); /* ioctl.c */ extern int ext3_ioctl (struct inode *, struct file *, unsigned int, -- 2.30.9