diff options
author | Andreas Gruenbacher <agruenba@redhat.com> | 2016-06-14 12:22:27 -0500 |
---|---|---|
committer | Bob Peterson <rpeterso@redhat.com> | 2016-06-27 09:47:07 -0500 |
commit | 3ce37b2cb4917674fa5b776e857dcea94c0e0835 (patch) | |
tree | 76adc95997a6e5ba7668630597c0872dde734a45 /fs/gfs2/inode.h | |
parent | 1e875f5a95a28b5286165db9fa832b0773657ddb (diff) |
gfs2: Fix gfs2_lookup_by_inum lock inversion
The current gfs2_lookup_by_inum takes the glock of a presumed inode
identified by block number, verifies that the block is indeed an inode,
and then instantiates and reads the new inode via gfs2_inode_lookup.
However, instantiating a new inode may block on freeing a previous
instance of that inode (__wait_on_freeing_inode), and freeing an inode
requires to take the glock already held, leading to lock inversion and
deadlock.
Fix this by first instantiating the new inode, then verifying that the
block is an inode (if required), and then reading in the new inode, all
in gfs2_inode_lookup.
If the block we are looking for is not an inode, we discard the new
inode via iget_failed, which marks inodes as bad and unhashes them.
Other tasks waiting on that inode will get back a bad inode back from
ilookup or iget_locked; in that case, retry the lookup.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Diffstat (limited to 'fs/gfs2/inode.h')
-rw-r--r-- | fs/gfs2/inode.h | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index e1af0d4aa308..443b46cfb8f2 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -94,7 +94,8 @@ err: } extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, - u64 no_addr, u64 no_formal_ino); + u64 no_addr, u64 no_formal_ino, + unsigned int blktype); extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, u64 *no_formal_ino, unsigned int blktype); |