diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2013-08-05 15:37:37 +0200 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-08-05 15:37:37 +0200 |
commit | 672fe15d091ce76d6fb98e489962e9add7c1ba4c (patch) | |
tree | 75760dceefa6de192465c14d6f72431d055fc772 /fs/reiserfs/super.c | |
parent | Linux 3.11-rc4 (diff) | |
download | linux-672fe15d091ce76d6fb98e489962e9add7c1ba4c.tar.xz linux-672fe15d091ce76d6fb98e489962e9add7c1ba4c.zip |
reiserfs: fix deadlock in umount
Since remove_proc_entry() started to wait for IO in progress (i.e.
since 2007 or so), the locking in fs/reiserfs/proc.c became wrong;
if procfs read happens between the moment when umount() locks the
victim superblock and removal of /proc/fs/reiserfs/<device>/*,
we'll get a deadlock - read will wait for s_umount (in sget(),
called by r_start()), while umount will wait in remove_proc_entry()
for that read to finish, holding s_umount all along.
Fortunately, the same change allows a much simpler race avoidance -
all we need to do is remove the procfs entries in the very beginning
of reiserfs ->kill_sb(); that'll guarantee that pointer to superblock
will remain valid for the duration for procfs IO, so we don't need
sget() to keep the sucker alive. As the matter of fact, we can
get rid of the home-grown iterator completely, and use single_open()
instead.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/reiserfs/super.c')
-rw-r--r-- | fs/reiserfs/super.c | 3 |
1 files changed, 1 insertions, 2 deletions
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index f8a23c3078f8..e2e202a07b31 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -499,6 +499,7 @@ int remove_save_link(struct inode *inode, int truncate) static void reiserfs_kill_sb(struct super_block *s) { if (REISERFS_SB(s)) { + reiserfs_proc_info_done(s); /* * Force any pending inode evictions to occur now. Any * inodes to be removed that have extended attributes @@ -554,8 +555,6 @@ static void reiserfs_put_super(struct super_block *s) REISERFS_SB(s)->reserved_blocks); } - reiserfs_proc_info_done(s); - reiserfs_write_unlock(s); mutex_destroy(&REISERFS_SB(s)->lock); kfree(s->s_fs_info); |