Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ext3: Replace lock/unlock_super() with an explicit lock for the orphan list

Use a separate lock to protect the orphan list, so we can stop
overloading the use of lock_super().

Port of ext4 commit 3b9d4ed26680771295d904a6b83e88e620780893
by Theodore Ts'o <tytso@mit.edu>.

CC: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Jan Kara <jack@suse.cz>

authored by

Eric Sandeen and committed by
Jan Kara
b8a052d0 4854a5f0

+13 -9
+11 -9
fs/ext3/namei.c
··· 1920 1920 struct ext3_iloc iloc; 1921 1921 int err = 0, rc; 1922 1922 1923 - lock_super(sb); 1923 + mutex_lock(&EXT3_SB(sb)->s_orphan_lock); 1924 1924 if (!list_empty(&EXT3_I(inode)->i_orphan)) 1925 1925 goto out_unlock; 1926 1926 ··· 1929 1929 1930 1930 /* @@@ FIXME: Observation from aviro: 1931 1931 * I think I can trigger J_ASSERT in ext3_orphan_add(). We block 1932 - * here (on lock_super()), so race with ext3_link() which might bump 1932 + * here (on s_orphan_lock), so race with ext3_link() which might bump 1933 1933 * ->i_nlink. For, say it, character device. Not a regular file, 1934 1934 * not a directory, not a symlink and ->i_nlink > 0. 1935 + * 1936 + * tytso, 4/25/2009: I'm not sure how that could happen; 1937 + * shouldn't the fs core protect us from these sort of 1938 + * unlink()/link() races? 1935 1939 */ 1936 1940 J_ASSERT ((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || 1937 1941 S_ISLNK(inode->i_mode)) || inode->i_nlink == 0); ··· 1972 1968 jbd_debug(4, "orphan inode %lu will point to %d\n", 1973 1969 inode->i_ino, NEXT_ORPHAN(inode)); 1974 1970 out_unlock: 1975 - unlock_super(sb); 1971 + mutex_unlock(&EXT3_SB(sb)->s_orphan_lock); 1976 1972 ext3_std_error(inode->i_sb, err); 1977 1973 return err; 1978 1974 } ··· 1990 1986 struct ext3_iloc iloc; 1991 1987 int err = 0; 1992 1988 1993 - lock_super(inode->i_sb); 1994 - if (list_empty(&ei->i_orphan)) { 1995 - unlock_super(inode->i_sb); 1996 - return 0; 1997 - } 1989 + mutex_lock(&EXT3_SB(inode->i_sb)->s_orphan_lock); 1990 + if (list_empty(&ei->i_orphan)) 1991 + goto out; 1998 1992 1999 1993 ino_next = NEXT_ORPHAN(inode); 2000 1994 prev = ei->i_orphan.prev; ··· 2042 2040 out_err: 2043 2041 ext3_std_error(inode->i_sb, err); 2044 2042 out: 2045 - unlock_super(inode->i_sb); 2043 + mutex_unlock(&EXT3_SB(inode->i_sb)->s_orphan_lock); 2046 2044 return err; 2047 2045 2048 2046 out_brelse:
+1
fs/ext3/super.c
··· 1928 1928 sb->dq_op = &ext3_quota_operations; 1929 1929 #endif 1930 1930 INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */ 1931 + mutex_init(&sbi->s_orphan_lock); 1931 1932 1932 1933 sb->s_root = NULL; 1933 1934
+1
include/linux/ext3_fs_sb.h
··· 72 72 struct inode * s_journal_inode; 73 73 struct journal_s * s_journal; 74 74 struct list_head s_orphan; 75 + struct mutex s_orphan_lock; 75 76 unsigned long s_commit_interval; 76 77 struct block_device *journal_bdev; 77 78 #ifdef CONFIG_JBD_DEBUG