]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Lachlan McIlroy <lmcilroy@redhat.com> |
2 | Date: Fri, 24 Apr 2009 02:18:00 +0000 (-0400) | |
3 | Subject: xfs_file_last_byte() needs to acquire ilock | |
4 | Patch-mainline: 2.6.30-rc5 | |
5 | Git-commit: def6b3ba56b637d58126ef67fc19bab57945fcc4 | |
6 | References: SGI:PV963454 bnc#487987 | |
7 | ||
8 | xfs_file_last_byte() needs to acquire ilock | |
9 | ||
10 | We had some systems crash with this stack: | |
11 | ||
12 | [<a00000010000cb20>] ia64_leave_kernel+0x0/0x280 | |
13 | [<a00000021291ca00>] xfs_bmbt_get_startoff+0x0/0x20 [xfs] | |
14 | [<a0000002129080b0>] xfs_bmap_last_offset+0x210/0x280 [xfs] | |
15 | [<a00000021295b010>] xfs_file_last_byte+0x70/0x1a0 [xfs] | |
16 | [<a00000021295b200>] xfs_itruncate_start+0xc0/0x1a0 [xfs] | |
17 | [<a0000002129935f0>] xfs_inactive_free_eofblocks+0x290/0x460 [xfs] | |
18 | [<a000000212998fb0>] xfs_release+0x1b0/0x240 [xfs] | |
19 | [<a0000002129ad930>] xfs_file_release+0x70/0xa0 [xfs] | |
20 | [<a000000100162ea0>] __fput+0x1a0/0x420 | |
21 | [<a000000100163160>] fput+0x40/0x60 | |
22 | ||
23 | The problem here is that xfs_file_last_byte() does not acquire the | |
24 | inode lock and can therefore race with another thread that is modifying | |
25 | the extext list. While xfs_bmap_last_offset() is trying to lookup | |
26 | what was the last extent some extents were merged and the extent list | |
27 | shrunk so the index we lookup is now beyond the end of the extent list | |
28 | and potentially in a freed buffer. | |
29 | ||
30 | Signed-off-by: Lachlan McIlroy <lmcilroy@redhat.com> | |
31 | Reviewed-by: Christoph Hellwig <hch@lst.de> | |
32 | Reviewed-by: Felix Blyakher <felixb@sgi.com> | |
33 | Signed-off-by: Felix Blyakher <felixb@sgi.com> | |
34 | Acked-by: Jeff Mahoney <jeffm@suse.com> | |
35 | --- | |
36 | ||
37 | fs/xfs/xfs_inode.c | 2 ++ | |
38 | 1 file changed, 2 insertions(+) | |
39 | ||
40 | --- a/fs/xfs/xfs_inode.c | |
41 | +++ b/fs/xfs/xfs_inode.c | |
42 | @@ -1306,8 +1306,10 @@ xfs_file_last_byte( | |
43 | * necessary. | |
44 | */ | |
45 | if (ip->i_df.if_flags & XFS_IFEXTENTS) { | |
46 | + xfs_ilock(ip, XFS_ILOCK_SHARED); | |
47 | error = xfs_bmap_last_offset(NULL, ip, &last_block, | |
48 | XFS_DATA_FORK); | |
49 | + xfs_iunlock(ip, XFS_ILOCK_SHARED); | |
50 | if (error) { | |
51 | last_block = 0; | |
52 | } |