From mboxrd@z Thu Jan 1 00:00:00 1970 From: Theodore Ts'o Subject: [PATCH] ext4: atomically set inode->i_flags in ext4_set_inode_flags() Date: Mon, 24 Mar 2014 14:43:59 -0400 Message-ID: <1395686639-1853-1-git-send-email-tytso@mit.edu> Cc: Theodore Ts'o , stable@kernel.org To: Ext4 Developers List Return-path: Received: from imap.thunk.org ([74.207.234.97]:45384 "EHLO imap.thunk.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753434AbaCXSoE (ORCPT ); Mon, 24 Mar 2014 14:44:04 -0400 Sender: linux-ext4-owner@vger.kernel.org List-ID: Use cmpxchg() to atomically set i_flags instead of clearing out the S_IMMUTABLE, S_APPEND, etc. flags and then setting them from the EXT4_IMMUTABLE_FL, EXT4_APPEND_FL flags, since this opens up a race where an immutable file has the immutable flag cleared for a brief window of time. Reported-by: Petr Matousek Signed-off-by: "Theodore Ts'o" Cc: stable@kernel.org --- fs/ext4/inode.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index b5e182a..169fff3 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3937,19 +3937,26 @@ int ext4_get_inode_loc(struct inode *inode, struct ext4_iloc *iloc) void ext4_set_inode_flags(struct inode *inode) { - unsigned int flags = EXT4_I(inode)->i_flags; - - inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); - if (flags & EXT4_SYNC_FL) - inode->i_flags |= S_SYNC; - if (flags & EXT4_APPEND_FL) - inode->i_flags |= S_APPEND; - if (flags & EXT4_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; - if (flags & EXT4_NOATIME_FL) - inode->i_flags |= S_NOATIME; - if (flags & EXT4_DIRSYNC_FL) - inode->i_flags |= S_DIRSYNC; + unsigned int flags; + unsigned int old_fl, new_fl; + + do { + flags = EXT4_I(inode)->i_flags; + old_fl = inode->i_flags; + new_fl = old_fl & + ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); + + if (flags & EXT4_SYNC_FL) + new_fl |= S_SYNC; + if (flags & EXT4_APPEND_FL) + new_fl |= S_APPEND; + if (flags & EXT4_IMMUTABLE_FL) + new_fl |= S_IMMUTABLE; + if (flags & EXT4_NOATIME_FL) + new_fl |= S_NOATIME; + if (flags & EXT4_DIRSYNC_FL) + new_fl |= S_DIRSYNC; + } while (cmpxchg(&inode->i_flags, old_fl, new_fl) != old_fl); } /* Propagate flags from i_flags to EXT4_I(inode)->i_flags */ -- 1.9.0