aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLachlan McIlroy <lmcilroy@redhat.com>2009-04-23 22:18:00 -0400
committerFelix Blyakher <felixb@sgi.com>2009-04-30 01:25:25 -0400
commitdef6b3ba56b637d58126ef67fc19bab57945fcc4 (patch)
tree983618561a50a6f9a423577c7fcd46fc1c539a62
parentdc2a5536d633dd2318f82f3d5ad3c9e43cfc21d7 (diff)
xfs_file_last_byte() needs to acquire ilock
We had some systems crash with this stack: [<a00000010000cb20>] ia64_leave_kernel+0x0/0x280 [<a00000021291ca00>] xfs_bmbt_get_startoff+0x0/0x20 [xfs] [<a0000002129080b0>] xfs_bmap_last_offset+0x210/0x280 [xfs] [<a00000021295b010>] xfs_file_last_byte+0x70/0x1a0 [xfs] [<a00000021295b200>] xfs_itruncate_start+0xc0/0x1a0 [xfs] [<a0000002129935f0>] xfs_inactive_free_eofblocks+0x290/0x460 [xfs] [<a000000212998fb0>] xfs_release+0x1b0/0x240 [xfs] [<a0000002129ad930>] xfs_file_release+0x70/0xa0 [xfs] [<a000000100162ea0>] __fput+0x1a0/0x420 [<a000000100163160>] fput+0x40/0x60 The problem here is that xfs_file_last_byte() does not acquire the inode lock and can therefore race with another thread that is modifying the extext list. While xfs_bmap_last_offset() is trying to lookup what was the last extent some extents were merged and the extent list shrunk so the index we lookup is now beyond the end of the extent list and potentially in a freed buffer. Signed-off-by: Lachlan McIlroy <lmcilroy@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Felix Blyakher <felixb@sgi.com> Signed-off-by: Felix Blyakher <felixb@sgi.com>
-rw-r--r--fs/xfs/xfs_inode.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index e7ae08d1df48..123b20c8cbf2 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1258,8 +1258,10 @@ xfs_file_last_byte(
1258 * necessary. 1258 * necessary.
1259 */ 1259 */
1260 if (ip->i_df.if_flags & XFS_IFEXTENTS) { 1260 if (ip->i_df.if_flags & XFS_IFEXTENTS) {
1261 xfs_ilock(ip, XFS_ILOCK_SHARED);
1261 error = xfs_bmap_last_offset(NULL, ip, &last_block, 1262 error = xfs_bmap_last_offset(NULL, ip, &last_block,
1262 XFS_DATA_FORK); 1263 XFS_DATA_FORK);
1264 xfs_iunlock(ip, XFS_ILOCK_SHARED);
1263 if (error) { 1265 if (error) {
1264 last_block = 0; 1266 last_block = 0;
1265 } 1267 }