When we're updating timestamps in an inode, search for that inode under RCU
conditions to avoid holding the icache lock if we can.

Signed-off-by: David Howells <[email protected]>
cc: "Theodore Ts'o" <[email protected]>
cc: Andreas Dilger <[email protected]>
cc: [email protected]
---

 fs/ext4/inode.c |   41 +++++++++++++++++++++--------------------
 1 file changed, 21 insertions(+), 20 deletions(-)

diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index b32a57bc5d5d..13e928ae70e5 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -5144,21 +5144,23 @@ static int ext4_inode_blocks_set(handle_t *handle,
        return 0;
 }
 
-struct other_inode {
-       unsigned long           orig_ino;
-       struct ext4_inode       *raw_inode;
-};
-
-static int other_inode_match(struct inode * inode, unsigned long ino,
-                            void *data)
+static void __ext4_update_other_inode_time(struct super_block *sb,
+                                          unsigned long orig_ino,
+                                          unsigned long ino,
+                                          struct ext4_inode *raw_inode)
 {
-       struct other_inode *oi = (struct other_inode *) data;
+       struct inode *inode;
+
+       inode = find_inode_by_ino_rcu(sb, ino);
+       if (!inode)
+               return;
 
        if ((inode->i_ino != ino) ||
            (inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW |
                               I_DIRTY_INODE)) ||
            ((inode->i_state & I_DIRTY_TIME) == 0))
-               return 0;
+               return;
+
        spin_lock(&inode->i_lock);
        if (((inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW |
                                I_DIRTY_INODE)) == 0) &&
@@ -5169,16 +5171,15 @@ static int other_inode_match(struct inode * inode, 
unsigned long ino,
                spin_unlock(&inode->i_lock);
 
                spin_lock(&ei->i_raw_lock);
-               EXT4_INODE_SET_XTIME(i_ctime, inode, oi->raw_inode);
-               EXT4_INODE_SET_XTIME(i_mtime, inode, oi->raw_inode);
-               EXT4_INODE_SET_XTIME(i_atime, inode, oi->raw_inode);
-               ext4_inode_csum_set(inode, oi->raw_inode, ei);
+               EXT4_INODE_SET_XTIME(i_ctime, inode, raw_inode);
+               EXT4_INODE_SET_XTIME(i_mtime, inode, raw_inode);
+               EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode);
+               ext4_inode_csum_set(inode, raw_inode, ei);
                spin_unlock(&ei->i_raw_lock);
-               trace_ext4_other_inode_update_time(inode, oi->orig_ino);
-               return -1;
+               trace_ext4_other_inode_update_time(inode, orig_ino);
+               return;
        }
        spin_unlock(&inode->i_lock);
-       return -1;
 }
 
 /*
@@ -5188,24 +5189,24 @@ static int other_inode_match(struct inode * inode, 
unsigned long ino,
 static void ext4_update_other_inodes_time(struct super_block *sb,
                                          unsigned long orig_ino, char *buf)
 {
-       struct other_inode oi;
        unsigned long ino;
        int i, inodes_per_block = EXT4_SB(sb)->s_inodes_per_block;
        int inode_size = EXT4_INODE_SIZE(sb);
 
-       oi.orig_ino = orig_ino;
        /*
         * Calculate the first inode in the inode table block.  Inode
         * numbers are one-based.  That is, the first inode in a block
         * (assuming 4k blocks and 256 byte inodes) is (n*16 + 1).
         */
        ino = ((orig_ino - 1) & ~(inodes_per_block - 1)) + 1;
+       rcu_read_lock();
        for (i = 0; i < inodes_per_block; i++, ino++, buf += inode_size) {
                if (ino == orig_ino)
                        continue;
-               oi.raw_inode = (struct ext4_inode *) buf;
-               (void) find_inode_nowait(sb, ino, other_inode_match, &oi);
+               __ext4_update_other_inode_time(sb, orig_ino, ino,
+                                              (struct ext4_inode *)buf);
        }
+       rcu_read_unlock();
 }
 
 /*

Reply via email to