diff options
| author | Stephen Lord <lord@sgi.com> | 2003-06-19 04:22:47 -0500 |
|---|---|---|
| committer | Stephen Lord <lord@sgi.com> | 2003-06-19 04:22:47 -0500 |
| commit | cecd52a72d18334f3d417f92828b8b78e72d0a21 (patch) | |
| tree | 291cc4eaccf9f1db86e119e134d107195499abd5 | |
| parent | f8b4e5fa1b07e6dbdde7cd4b3ffd7ec0c3f60158 (diff) | |
[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
| -rw-r--r-- | fs/xfs/xfs_iget.c | 10 | ||||
| -rw-r--r-- | fs/xfs/xfs_inode.h | 1 | ||||
| -rw-r--r-- | fs/xfs/xfs_vnodeops.c | 25 |
3 files changed, 25 insertions, 11 deletions
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index be218976502e..267d2f95211c 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c @@ -214,7 +214,13 @@ again: XFS_STATS_INC(xfsstats.xs_ig_found); + ip->i_flags &= ~XFS_IRECLAIMABLE; read_unlock(&ih->ih_lock); + + XFS_MOUNT_ILOCK(mp); + list_del_init(&ip->i_reclaim); + XFS_MOUNT_IUNLOCK(mp); + goto finish_inode; } else if (vp != inode_vp) { @@ -253,10 +259,6 @@ finish_inode: 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", (inst_t *)__return_address); goto return_ip; diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 614ddb6d2018..be2c12208fc6 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -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_IQUIESCE 0x0004 /* we have started quiescing for this inode */ #define XFS_IRECLAIM 0x0008 /* we have started reclaiming this inode */ +#define XFS_IRECLAIMABLE 0x0010 /* inode can be reclaimed */ /* * Flags for inode locking. diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 2bb9ee6d334f..b51c355ebd88 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -3930,6 +3930,7 @@ xfs_reclaim( */ if (!ip->i_update_core && (ip->i_itemp == NULL)) { xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_iflock(ip); return xfs_finish_reclaim(ip, 1, XFS_IFLUSH_DELWRI_ELSE_SYNC); } else { xfs_mount_t *mp = ip->i_mount; @@ -3938,7 +3939,7 @@ xfs_reclaim( XFS_MOUNT_ILOCK(mp); vn_bhv_remove(VN_BHV_HEAD(vp), XFS_ITOBHV(ip)); list_add_tail(&ip->i_reclaim, &mp->m_del_inodes); - + ip->i_flags |= XFS_IRECLAIMABLE; XFS_MOUNT_IUNLOCK(mp); } return 0; @@ -3953,19 +3954,20 @@ xfs_finish_reclaim( xfs_ihash_t *ih = ip->i_hash; int error; - if (!locked) - xfs_ilock(ip, XFS_ILOCK_EXCL); - /* The hash lock here protects a thread in xfs_iget_core from * racing with us on linking the inode back with a vnode. * Once we have the XFS_IRECLAIM flag set it will not touch * us. */ 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); - if (!locked) + if (locked) { + xfs_ifunlock(ip); xfs_iunlock(ip, XFS_ILOCK_EXCL); + } return(1); } ip->i_flags |= XFS_IRECLAIM; @@ -3984,6 +3986,7 @@ xfs_finish_reclaim( */ if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { if (!locked) { + xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_iflock(ip); } @@ -4007,8 +4010,16 @@ xfs_finish_reclaim( ASSERT(ip->i_update_core == 0); ASSERT(ip->i_itemp == NULL || ip->i_itemp->ili_format.ilf_fields == 0); + 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_iunlock(ip, XFS_ILOCK_EXCL); xfs_ireclaim(ip); return 0; |
