Commit cecd52a7 authored by Stephen Lord's avatar Stephen Lord

[XFS] Fix deadlock between xfs_finish_reclaim and xfs_iget_core. An inode being

reclaimed and removed from memory by one thread while another thread
is attempting to reuse the inode and bring it back to life. There
was a window between the iget starting to reuse the inode and the
reclaim starting. Close the window by marking the inode as being
reused under the hash lock, and by abandoning the reclaim if this
is detected when it obtains the hash lock.

SGI Modid: 2.5.x-xfs:slinx:151123a
parent f8b4e5fa
...@@ -214,7 +214,13 @@ xfs_iget_core( ...@@ -214,7 +214,13 @@ xfs_iget_core(
XFS_STATS_INC(xfsstats.xs_ig_found); XFS_STATS_INC(xfsstats.xs_ig_found);
ip->i_flags &= ~XFS_IRECLAIMABLE;
read_unlock(&ih->ih_lock); read_unlock(&ih->ih_lock);
XFS_MOUNT_ILOCK(mp);
list_del_init(&ip->i_reclaim);
XFS_MOUNT_IUNLOCK(mp);
goto finish_inode; goto finish_inode;
} else if (vp != inode_vp) { } else if (vp != inode_vp) {
...@@ -253,10 +259,6 @@ xfs_iget_core( ...@@ -253,10 +259,6 @@ xfs_iget_core(
xfs_iocore_inode_reinit(ip); xfs_iocore_inode_reinit(ip);
} }
XFS_MOUNT_ILOCK(mp);
list_del_init(&ip->i_reclaim);
XFS_MOUNT_IUNLOCK(mp);
vn_trace_exit(vp, "xfs_iget.found", vn_trace_exit(vp, "xfs_iget.found",
(inst_t *)__return_address); (inst_t *)__return_address);
goto return_ip; goto return_ip;
......
...@@ -362,6 +362,7 @@ void xfs_ifork_next_set(xfs_inode_t *ip, int w, int n); ...@@ -362,6 +362,7 @@ void xfs_ifork_next_set(xfs_inode_t *ip, int w, int n);
#define XFS_IUIOSZ 0x0002 /* inode i/o sizes have been explicitly set */ #define XFS_IUIOSZ 0x0002 /* inode i/o sizes have been explicitly set */
#define XFS_IQUIESCE 0x0004 /* we have started quiescing for this inode */ #define XFS_IQUIESCE 0x0004 /* we have started quiescing for this inode */
#define XFS_IRECLAIM 0x0008 /* we have started reclaiming this inode */ #define XFS_IRECLAIM 0x0008 /* we have started reclaiming this inode */
#define XFS_IRECLAIMABLE 0x0010 /* inode can be reclaimed */
/* /*
* Flags for inode locking. * Flags for inode locking.
......
...@@ -3930,6 +3930,7 @@ xfs_reclaim( ...@@ -3930,6 +3930,7 @@ xfs_reclaim(
*/ */
if (!ip->i_update_core && (ip->i_itemp == NULL)) { if (!ip->i_update_core && (ip->i_itemp == NULL)) {
xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_iflock(ip);
return xfs_finish_reclaim(ip, 1, XFS_IFLUSH_DELWRI_ELSE_SYNC); return xfs_finish_reclaim(ip, 1, XFS_IFLUSH_DELWRI_ELSE_SYNC);
} else { } else {
xfs_mount_t *mp = ip->i_mount; xfs_mount_t *mp = ip->i_mount;
...@@ -3938,7 +3939,7 @@ xfs_reclaim( ...@@ -3938,7 +3939,7 @@ xfs_reclaim(
XFS_MOUNT_ILOCK(mp); XFS_MOUNT_ILOCK(mp);
vn_bhv_remove(VN_BHV_HEAD(vp), XFS_ITOBHV(ip)); vn_bhv_remove(VN_BHV_HEAD(vp), XFS_ITOBHV(ip));
list_add_tail(&ip->i_reclaim, &mp->m_del_inodes); list_add_tail(&ip->i_reclaim, &mp->m_del_inodes);
ip->i_flags |= XFS_IRECLAIMABLE;
XFS_MOUNT_IUNLOCK(mp); XFS_MOUNT_IUNLOCK(mp);
} }
return 0; return 0;
...@@ -3953,19 +3954,20 @@ xfs_finish_reclaim( ...@@ -3953,19 +3954,20 @@ xfs_finish_reclaim(
xfs_ihash_t *ih = ip->i_hash; xfs_ihash_t *ih = ip->i_hash;
int error; int error;
if (!locked)
xfs_ilock(ip, XFS_ILOCK_EXCL);
/* The hash lock here protects a thread in xfs_iget_core from /* The hash lock here protects a thread in xfs_iget_core from
* racing with us on linking the inode back with a vnode. * racing with us on linking the inode back with a vnode.
* Once we have the XFS_IRECLAIM flag set it will not touch * Once we have the XFS_IRECLAIM flag set it will not touch
* us. * us.
*/ */
write_lock(&ih->ih_lock); write_lock(&ih->ih_lock);
if (ip->i_flags & XFS_IRECLAIM || (!locked && XFS_ITOV_NULL(ip))) { if ((ip->i_flags & XFS_IRECLAIM) ||
(!(ip->i_flags & XFS_IRECLAIMABLE) &&
(XFS_ITOV_NULL(ip) == NULL))) {
write_unlock(&ih->ih_lock); write_unlock(&ih->ih_lock);
if (!locked) if (locked) {
xfs_ifunlock(ip);
xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(ip, XFS_ILOCK_EXCL);
}
return(1); return(1);
} }
ip->i_flags |= XFS_IRECLAIM; ip->i_flags |= XFS_IRECLAIM;
...@@ -3984,6 +3986,7 @@ xfs_finish_reclaim( ...@@ -3984,6 +3986,7 @@ xfs_finish_reclaim(
*/ */
if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
if (!locked) { if (!locked) {
xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_iflock(ip); xfs_iflock(ip);
} }
...@@ -4007,8 +4010,16 @@ xfs_finish_reclaim( ...@@ -4007,8 +4010,16 @@ xfs_finish_reclaim(
ASSERT(ip->i_update_core == 0); ASSERT(ip->i_update_core == 0);
ASSERT(ip->i_itemp == NULL || ASSERT(ip->i_itemp == NULL ||
ip->i_itemp->ili_format.ilf_fields == 0); ip->i_itemp->ili_format.ilf_fields == 0);
}
xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(ip, XFS_ILOCK_EXCL);
} else if (locked) {
/*
* We are not interested in doing an iflush if we're
* in the process of shutting down the filesystem forcibly.
* So, just reclaim the inode.
*/
xfs_ifunlock(ip);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
}
xfs_ireclaim(ip); xfs_ireclaim(ip);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment