aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_inode.c
diff options
context:
space:
mode:
authorDavid Chinner <dgc@sgi.com>2006-09-27 21:06:03 -0400
committerTim Shimmin <tes@sgi.com>2006-09-27 21:06:03 -0400
commitf273ab848b7cbc0088b0ac7457b3769e6566074e (patch)
tree27f1b0ce7b056f77e7105284524cbdb658943ae5 /fs/xfs/xfs_inode.c
parent01106eae97b70399ce5a273a3cceb5246e8d9cc8 (diff)
[XFS] Really fix use after free in xfs_iunpin.
The previous attempts to fix the linux inode use-after-free in xfs_iunpin simply made the problem harder to hit. We actually need complete exclusion between xfs_reclaim and xfs_iunpin, as well as ensuring that the i_flags are consistent during both of these functions. Introduce a new spinlock for exclusion and the i_flags, and fix up xfs_iunpin to use igrab before marking the inode dirty. SGI-PV: 952967 SGI-Modid: xfs-linux-melb:xfs-kern:26964a Signed-off-by: David Chinner <dgc@sgi.com> Signed-off-by: Tim Shimmin <tes@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_inode.c')
-rw-r--r--fs/xfs/xfs_inode.c23
1 files changed, 20 insertions, 3 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 66a78287a957..c27d7d495aa0 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -867,6 +867,7 @@ xfs_iread(
867 ip = kmem_zone_zalloc(xfs_inode_zone, KM_SLEEP); 867 ip = kmem_zone_zalloc(xfs_inode_zone, KM_SLEEP);
868 ip->i_ino = ino; 868 ip->i_ino = ino;
869 ip->i_mount = mp; 869 ip->i_mount = mp;
870 spin_lock_init(&ip->i_flags_lock);
870 871
871 /* 872 /*
872 * Get pointer's to the on-disk inode and the buffer containing it. 873 * Get pointer's to the on-disk inode and the buffer containing it.
@@ -2214,7 +2215,9 @@ xfs_ifree_cluster(
2214 2215
2215 if (ip == free_ip) { 2216 if (ip == free_ip) {
2216 if (xfs_iflock_nowait(ip)) { 2217 if (xfs_iflock_nowait(ip)) {
2218 spin_lock(&ip->i_flags_lock);
2217 ip->i_flags |= XFS_ISTALE; 2219 ip->i_flags |= XFS_ISTALE;
2220 spin_unlock(&ip->i_flags_lock);
2218 2221
2219 if (xfs_inode_clean(ip)) { 2222 if (xfs_inode_clean(ip)) {
2220 xfs_ifunlock(ip); 2223 xfs_ifunlock(ip);
@@ -2228,7 +2231,9 @@ xfs_ifree_cluster(
2228 2231
2229 if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) { 2232 if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
2230 if (xfs_iflock_nowait(ip)) { 2233 if (xfs_iflock_nowait(ip)) {
2234 spin_lock(&ip->i_flags_lock);
2231 ip->i_flags |= XFS_ISTALE; 2235 ip->i_flags |= XFS_ISTALE;
2236 spin_unlock(&ip->i_flags_lock);
2232 2237
2233 if (xfs_inode_clean(ip)) { 2238 if (xfs_inode_clean(ip)) {
2234 xfs_ifunlock(ip); 2239 xfs_ifunlock(ip);
@@ -2258,7 +2263,9 @@ xfs_ifree_cluster(
2258 AIL_LOCK(mp,s); 2263 AIL_LOCK(mp,s);
2259 iip->ili_flush_lsn = iip->ili_item.li_lsn; 2264 iip->ili_flush_lsn = iip->ili_item.li_lsn;
2260 AIL_UNLOCK(mp, s); 2265 AIL_UNLOCK(mp, s);
2266 spin_lock(&iip->ili_inode->i_flags_lock);
2261 iip->ili_inode->i_flags |= XFS_ISTALE; 2267 iip->ili_inode->i_flags |= XFS_ISTALE;
2268 spin_unlock(&iip->ili_inode->i_flags_lock);
2262 pre_flushed++; 2269 pre_flushed++;
2263 } 2270 }
2264 lip = lip->li_bio_list; 2271 lip = lip->li_bio_list;
@@ -2754,19 +2761,29 @@ xfs_iunpin(
2754 * call as the inode reclaim may be blocked waiting for 2761 * call as the inode reclaim may be blocked waiting for
2755 * the inode to become unpinned. 2762 * the inode to become unpinned.
2756 */ 2763 */
2764 struct inode *inode = NULL;
2765
2766 spin_lock(&ip->i_flags_lock);
2757 if (!(ip->i_flags & (XFS_IRECLAIM|XFS_IRECLAIMABLE))) { 2767 if (!(ip->i_flags & (XFS_IRECLAIM|XFS_IRECLAIMABLE))) {
2758 bhv_vnode_t *vp = XFS_ITOV_NULL(ip); 2768 bhv_vnode_t *vp = XFS_ITOV_NULL(ip);
2759 2769
2760 /* make sync come back and flush this inode */ 2770 /* make sync come back and flush this inode */
2761 if (vp) { 2771 if (vp) {
2762 struct inode *inode = vn_to_inode(vp); 2772 inode = vn_to_inode(vp);
2763 2773
2764 if (!(inode->i_state & 2774 if (!(inode->i_state &
2765 (I_NEW|I_FREEING|I_CLEAR))) 2775 (I_NEW|I_FREEING|I_CLEAR))) {
2766 mark_inode_dirty_sync(inode); 2776 inode = igrab(inode);
2777 if (inode)
2778 mark_inode_dirty_sync(inode);
2779 } else
2780 inode = NULL;
2767 } 2781 }
2768 } 2782 }
2783 spin_unlock(&ip->i_flags_lock);
2769 wake_up(&ip->i_ipin_wait); 2784 wake_up(&ip->i_ipin_wait);
2785 if (inode)
2786 iput(inode);
2770 } 2787 }
2771} 2788}
2772 2789