diff options
author | Theodore Ts'o <tytso@mit.edu> | 2009-04-25 22:54:04 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2009-04-25 22:54:04 -0400 |
commit | 3b9d4ed26680771295d904a6b83e88e620780893 (patch) | |
tree | 905b0e95697839c446c86250cf38dd256f5e846a /fs | |
parent | a63c9eb2ce6f5028da90f282798232c4f398ceb8 (diff) |
ext4: 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().
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/ext4_sb.h | 1 | ||||
-rw-r--r-- | fs/ext4/namei.c | 20 | ||||
-rw-r--r-- | fs/ext4/super.c | 1 |
3 files changed, 13 insertions, 9 deletions
diff --git a/fs/ext4/ext4_sb.h b/fs/ext4/ext4_sb.h index 57b71fefbccf..4bda2f75d426 100644 --- a/fs/ext4/ext4_sb.h +++ b/fs/ext4/ext4_sb.h | |||
@@ -71,6 +71,7 @@ struct ext4_sb_info { | |||
71 | struct inode *s_journal_inode; | 71 | struct inode *s_journal_inode; |
72 | struct journal_s *s_journal; | 72 | struct journal_s *s_journal; |
73 | struct list_head s_orphan; | 73 | struct list_head s_orphan; |
74 | struct mutex s_orphan_lock; | ||
74 | unsigned long s_commit_interval; | 75 | unsigned long s_commit_interval; |
75 | u32 s_max_batch_time; | 76 | u32 s_max_batch_time; |
76 | u32 s_min_batch_time; | 77 | u32 s_min_batch_time; |
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 22098e1cd085..8018e49a7287 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -1997,7 +1997,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode) | |||
1997 | if (!ext4_handle_valid(handle)) | 1997 | if (!ext4_handle_valid(handle)) |
1998 | return 0; | 1998 | return 0; |
1999 | 1999 | ||
2000 | lock_super(sb); | 2000 | mutex_lock(&EXT4_SB(sb)->s_orphan_lock); |
2001 | if (!list_empty(&EXT4_I(inode)->i_orphan)) | 2001 | if (!list_empty(&EXT4_I(inode)->i_orphan)) |
2002 | goto out_unlock; | 2002 | goto out_unlock; |
2003 | 2003 | ||
@@ -2006,9 +2006,13 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode) | |||
2006 | 2006 | ||
2007 | /* @@@ FIXME: Observation from aviro: | 2007 | /* @@@ FIXME: Observation from aviro: |
2008 | * I think I can trigger J_ASSERT in ext4_orphan_add(). We block | 2008 | * I think I can trigger J_ASSERT in ext4_orphan_add(). We block |
2009 | * here (on lock_super()), so race with ext4_link() which might bump | 2009 | * here (on s_orphan_lock), so race with ext4_link() which might bump |
2010 | * ->i_nlink. For, say it, character device. Not a regular file, | 2010 | * ->i_nlink. For, say it, character device. Not a regular file, |
2011 | * not a directory, not a symlink and ->i_nlink > 0. | 2011 | * not a directory, not a symlink and ->i_nlink > 0. |
2012 | * | ||
2013 | * tytso, 4/25/2009: I'm not sure how that could happen; | ||
2014 | * shouldn't the fs core protect us from these sort of | ||
2015 | * unlink()/link() races? | ||
2012 | */ | 2016 | */ |
2013 | J_ASSERT((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || | 2017 | J_ASSERT((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || |
2014 | S_ISLNK(inode->i_mode)) || inode->i_nlink == 0); | 2018 | S_ISLNK(inode->i_mode)) || inode->i_nlink == 0); |
@@ -2045,7 +2049,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode) | |||
2045 | jbd_debug(4, "orphan inode %lu will point to %d\n", | 2049 | jbd_debug(4, "orphan inode %lu will point to %d\n", |
2046 | inode->i_ino, NEXT_ORPHAN(inode)); | 2050 | inode->i_ino, NEXT_ORPHAN(inode)); |
2047 | out_unlock: | 2051 | out_unlock: |
2048 | unlock_super(sb); | 2052 | mutex_unlock(&EXT4_SB(sb)->s_orphan_lock); |
2049 | ext4_std_error(inode->i_sb, err); | 2053 | ext4_std_error(inode->i_sb, err); |
2050 | return err; | 2054 | return err; |
2051 | } | 2055 | } |
@@ -2066,11 +2070,9 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode) | |||
2066 | if (!ext4_handle_valid(handle)) | 2070 | if (!ext4_handle_valid(handle)) |
2067 | return 0; | 2071 | return 0; |
2068 | 2072 | ||
2069 | lock_super(inode->i_sb); | 2073 | mutex_lock(&EXT4_SB(inode->i_sb)->s_orphan_lock); |
2070 | if (list_empty(&ei->i_orphan)) { | 2074 | if (list_empty(&ei->i_orphan)) |
2071 | unlock_super(inode->i_sb); | 2075 | goto out; |
2072 | return 0; | ||
2073 | } | ||
2074 | 2076 | ||
2075 | ino_next = NEXT_ORPHAN(inode); | 2077 | ino_next = NEXT_ORPHAN(inode); |
2076 | prev = ei->i_orphan.prev; | 2078 | prev = ei->i_orphan.prev; |
@@ -2120,7 +2122,7 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode) | |||
2120 | out_err: | 2122 | out_err: |
2121 | ext4_std_error(inode->i_sb, err); | 2123 | ext4_std_error(inode->i_sb, err); |
2122 | out: | 2124 | out: |
2123 | unlock_super(inode->i_sb); | 2125 | mutex_unlock(&EXT4_SB(inode->i_sb)->s_orphan_lock); |
2124 | return err; | 2126 | return err; |
2125 | 2127 | ||
2126 | out_brelse: | 2128 | out_brelse: |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 45d0ada9bfce..7f43fde9554b 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -2645,6 +2645,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
2645 | sb->dq_op = &ext4_quota_operations; | 2645 | sb->dq_op = &ext4_quota_operations; |
2646 | #endif | 2646 | #endif |
2647 | INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */ | 2647 | INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */ |
2648 | mutex_init(&sbi->s_orphan_lock); | ||
2648 | 2649 | ||
2649 | sb->s_root = NULL; | 2650 | sb->s_root = NULL; |
2650 | 2651 | ||