diff options
author | Tiger Yang <tiger.yang@oracle.com> | 2013-08-13 19:00:58 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-08-13 20:57:49 -0400 |
commit | c7dd3392ad469e6ba125170ad29f881bed85b678 (patch) | |
tree | bdb444e27e72975da0a3ebad279392fb8b81929d /fs | |
parent | 6115ea288424c1ead077843b6cd22369dd2e08f9 (diff) |
ocfs2: fix NULL pointer dereference in ocfs2_duplicate_clusters_by_page
Since ocfs2_cow_file_pos will invoke ocfs2_refcount_icow with a NULL as
the struct file pointer, it finally result in a null pointer dereference
in ocfs2_duplicate_clusters_by_page.
This patch replace file pointer with inode pointer in
cow_duplicate_clusters to fix this issue.
[jeff.liu@oracle.com: rebased patch against linux-next tree]
Signed-off-by: Tiger Yang <tiger.yang@oracle.com>
Signed-off-by: Jie Liu <jeff.liu@oracle.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Mark Fasheh <mfasheh@suse.com>
Acked-by: Tao Ma <tm@tao.ma>
Tested-by: David Weber <wb@munzinger.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/aops.c | 2 | ||||
-rw-r--r-- | fs/ocfs2/file.c | 6 | ||||
-rw-r--r-- | fs/ocfs2/move_extents.c | 2 | ||||
-rw-r--r-- | fs/ocfs2/refcounttree.c | 53 | ||||
-rw-r--r-- | fs/ocfs2/refcounttree.h | 6 |
5 files changed, 16 insertions, 53 deletions
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 79736a28d84f..2abf97b2a592 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
@@ -1757,7 +1757,7 @@ try_again: | |||
1757 | goto out; | 1757 | goto out; |
1758 | } else if (ret == 1) { | 1758 | } else if (ret == 1) { |
1759 | clusters_need = wc->w_clen; | 1759 | clusters_need = wc->w_clen; |
1760 | ret = ocfs2_refcount_cow(inode, filp, di_bh, | 1760 | ret = ocfs2_refcount_cow(inode, di_bh, |
1761 | wc->w_cpos, wc->w_clen, UINT_MAX); | 1761 | wc->w_cpos, wc->w_clen, UINT_MAX); |
1762 | if (ret) { | 1762 | if (ret) { |
1763 | mlog_errno(ret); | 1763 | mlog_errno(ret); |
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 41000f223ca4..3261d71319ee 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -370,7 +370,7 @@ static int ocfs2_cow_file_pos(struct inode *inode, | |||
370 | if (!(ext_flags & OCFS2_EXT_REFCOUNTED)) | 370 | if (!(ext_flags & OCFS2_EXT_REFCOUNTED)) |
371 | goto out; | 371 | goto out; |
372 | 372 | ||
373 | return ocfs2_refcount_cow(inode, NULL, fe_bh, cpos, 1, cpos+1); | 373 | return ocfs2_refcount_cow(inode, fe_bh, cpos, 1, cpos+1); |
374 | 374 | ||
375 | out: | 375 | out: |
376 | return status; | 376 | return status; |
@@ -899,7 +899,7 @@ static int ocfs2_zero_extend_get_range(struct inode *inode, | |||
899 | zero_clusters = last_cpos - zero_cpos; | 899 | zero_clusters = last_cpos - zero_cpos; |
900 | 900 | ||
901 | if (needs_cow) { | 901 | if (needs_cow) { |
902 | rc = ocfs2_refcount_cow(inode, NULL, di_bh, zero_cpos, | 902 | rc = ocfs2_refcount_cow(inode, di_bh, zero_cpos, |
903 | zero_clusters, UINT_MAX); | 903 | zero_clusters, UINT_MAX); |
904 | if (rc) { | 904 | if (rc) { |
905 | mlog_errno(rc); | 905 | mlog_errno(rc); |
@@ -2078,7 +2078,7 @@ static int ocfs2_prepare_inode_for_refcount(struct inode *inode, | |||
2078 | 2078 | ||
2079 | *meta_level = 1; | 2079 | *meta_level = 1; |
2080 | 2080 | ||
2081 | ret = ocfs2_refcount_cow(inode, file, di_bh, cpos, clusters, UINT_MAX); | 2081 | ret = ocfs2_refcount_cow(inode, di_bh, cpos, clusters, UINT_MAX); |
2082 | if (ret) | 2082 | if (ret) |
2083 | mlog_errno(ret); | 2083 | mlog_errno(ret); |
2084 | out: | 2084 | out: |
diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c index f1fc172175b6..452068b45749 100644 --- a/fs/ocfs2/move_extents.c +++ b/fs/ocfs2/move_extents.c | |||
@@ -69,7 +69,7 @@ static int __ocfs2_move_extent(handle_t *handle, | |||
69 | u64 ino = ocfs2_metadata_cache_owner(context->et.et_ci); | 69 | u64 ino = ocfs2_metadata_cache_owner(context->et.et_ci); |
70 | u64 old_blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cpos); | 70 | u64 old_blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cpos); |
71 | 71 | ||
72 | ret = ocfs2_duplicate_clusters_by_page(handle, context->file, cpos, | 72 | ret = ocfs2_duplicate_clusters_by_page(handle, inode, cpos, |
73 | p_cpos, new_p_cpos, len); | 73 | p_cpos, new_p_cpos, len); |
74 | if (ret) { | 74 | if (ret) { |
75 | mlog_errno(ret); | 75 | mlog_errno(ret); |
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 9f6b96a09615..a70d604593b6 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c | |||
@@ -49,7 +49,6 @@ | |||
49 | 49 | ||
50 | struct ocfs2_cow_context { | 50 | struct ocfs2_cow_context { |
51 | struct inode *inode; | 51 | struct inode *inode; |
52 | struct file *file; | ||
53 | u32 cow_start; | 52 | u32 cow_start; |
54 | u32 cow_len; | 53 | u32 cow_len; |
55 | struct ocfs2_extent_tree data_et; | 54 | struct ocfs2_extent_tree data_et; |
@@ -66,7 +65,7 @@ struct ocfs2_cow_context { | |||
66 | u32 *num_clusters, | 65 | u32 *num_clusters, |
67 | unsigned int *extent_flags); | 66 | unsigned int *extent_flags); |
68 | int (*cow_duplicate_clusters)(handle_t *handle, | 67 | int (*cow_duplicate_clusters)(handle_t *handle, |
69 | struct file *file, | 68 | struct inode *inode, |
70 | u32 cpos, u32 old_cluster, | 69 | u32 cpos, u32 old_cluster, |
71 | u32 new_cluster, u32 new_len); | 70 | u32 new_cluster, u32 new_len); |
72 | }; | 71 | }; |
@@ -2922,14 +2921,12 @@ static int ocfs2_clear_cow_buffer(handle_t *handle, struct buffer_head *bh) | |||
2922 | } | 2921 | } |
2923 | 2922 | ||
2924 | int ocfs2_duplicate_clusters_by_page(handle_t *handle, | 2923 | int ocfs2_duplicate_clusters_by_page(handle_t *handle, |
2925 | struct file *file, | 2924 | struct inode *inode, |
2926 | u32 cpos, u32 old_cluster, | 2925 | u32 cpos, u32 old_cluster, |
2927 | u32 new_cluster, u32 new_len) | 2926 | u32 new_cluster, u32 new_len) |
2928 | { | 2927 | { |
2929 | int ret = 0, partial; | 2928 | int ret = 0, partial; |
2930 | struct inode *inode = file_inode(file); | 2929 | struct super_block *sb = inode->i_sb; |
2931 | struct ocfs2_caching_info *ci = INODE_CACHE(inode); | ||
2932 | struct super_block *sb = ocfs2_metadata_cache_get_super(ci); | ||
2933 | u64 new_block = ocfs2_clusters_to_blocks(sb, new_cluster); | 2930 | u64 new_block = ocfs2_clusters_to_blocks(sb, new_cluster); |
2934 | struct page *page; | 2931 | struct page *page; |
2935 | pgoff_t page_index; | 2932 | pgoff_t page_index; |
@@ -2978,13 +2975,6 @@ int ocfs2_duplicate_clusters_by_page(handle_t *handle, | |||
2978 | if (PAGE_CACHE_SIZE <= OCFS2_SB(sb)->s_clustersize) | 2975 | if (PAGE_CACHE_SIZE <= OCFS2_SB(sb)->s_clustersize) |
2979 | BUG_ON(PageDirty(page)); | 2976 | BUG_ON(PageDirty(page)); |
2980 | 2977 | ||
2981 | if (PageReadahead(page)) { | ||
2982 | page_cache_async_readahead(mapping, | ||
2983 | &file->f_ra, file, | ||
2984 | page, page_index, | ||
2985 | readahead_pages); | ||
2986 | } | ||
2987 | |||
2988 | if (!PageUptodate(page)) { | 2978 | if (!PageUptodate(page)) { |
2989 | ret = block_read_full_page(page, ocfs2_get_block); | 2979 | ret = block_read_full_page(page, ocfs2_get_block); |
2990 | if (ret) { | 2980 | if (ret) { |
@@ -3004,7 +2994,8 @@ int ocfs2_duplicate_clusters_by_page(handle_t *handle, | |||
3004 | } | 2994 | } |
3005 | } | 2995 | } |
3006 | 2996 | ||
3007 | ocfs2_map_and_dirty_page(inode, handle, from, to, | 2997 | ocfs2_map_and_dirty_page(inode, |
2998 | handle, from, to, | ||
3008 | page, 0, &new_block); | 2999 | page, 0, &new_block); |
3009 | mark_page_accessed(page); | 3000 | mark_page_accessed(page); |
3010 | unlock: | 3001 | unlock: |
@@ -3020,12 +3011,11 @@ unlock: | |||
3020 | } | 3011 | } |
3021 | 3012 | ||
3022 | int ocfs2_duplicate_clusters_by_jbd(handle_t *handle, | 3013 | int ocfs2_duplicate_clusters_by_jbd(handle_t *handle, |
3023 | struct file *file, | 3014 | struct inode *inode, |
3024 | u32 cpos, u32 old_cluster, | 3015 | u32 cpos, u32 old_cluster, |
3025 | u32 new_cluster, u32 new_len) | 3016 | u32 new_cluster, u32 new_len) |
3026 | { | 3017 | { |
3027 | int ret = 0; | 3018 | int ret = 0; |
3028 | struct inode *inode = file_inode(file); | ||
3029 | struct super_block *sb = inode->i_sb; | 3019 | struct super_block *sb = inode->i_sb; |
3030 | struct ocfs2_caching_info *ci = INODE_CACHE(inode); | 3020 | struct ocfs2_caching_info *ci = INODE_CACHE(inode); |
3031 | int i, blocks = ocfs2_clusters_to_blocks(sb, new_len); | 3021 | int i, blocks = ocfs2_clusters_to_blocks(sb, new_len); |
@@ -3150,7 +3140,7 @@ static int ocfs2_replace_clusters(handle_t *handle, | |||
3150 | 3140 | ||
3151 | /*If the old clusters is unwritten, no need to duplicate. */ | 3141 | /*If the old clusters is unwritten, no need to duplicate. */ |
3152 | if (!(ext_flags & OCFS2_EXT_UNWRITTEN)) { | 3142 | if (!(ext_flags & OCFS2_EXT_UNWRITTEN)) { |
3153 | ret = context->cow_duplicate_clusters(handle, context->file, | 3143 | ret = context->cow_duplicate_clusters(handle, context->inode, |
3154 | cpos, old, new, len); | 3144 | cpos, old, new, len); |
3155 | if (ret) { | 3145 | if (ret) { |
3156 | mlog_errno(ret); | 3146 | mlog_errno(ret); |
@@ -3428,35 +3418,12 @@ static int ocfs2_replace_cow(struct ocfs2_cow_context *context) | |||
3428 | return ret; | 3418 | return ret; |
3429 | } | 3419 | } |
3430 | 3420 | ||
3431 | static void ocfs2_readahead_for_cow(struct inode *inode, | ||
3432 | struct file *file, | ||
3433 | u32 start, u32 len) | ||
3434 | { | ||
3435 | struct address_space *mapping; | ||
3436 | pgoff_t index; | ||
3437 | unsigned long num_pages; | ||
3438 | int cs_bits = OCFS2_SB(inode->i_sb)->s_clustersize_bits; | ||
3439 | |||
3440 | if (!file) | ||
3441 | return; | ||
3442 | |||
3443 | mapping = file->f_mapping; | ||
3444 | num_pages = (len << cs_bits) >> PAGE_CACHE_SHIFT; | ||
3445 | if (!num_pages) | ||
3446 | num_pages = 1; | ||
3447 | |||
3448 | index = ((loff_t)start << cs_bits) >> PAGE_CACHE_SHIFT; | ||
3449 | page_cache_sync_readahead(mapping, &file->f_ra, file, | ||
3450 | index, num_pages); | ||
3451 | } | ||
3452 | |||
3453 | /* | 3421 | /* |
3454 | * Starting at cpos, try to CoW write_len clusters. Don't CoW | 3422 | * Starting at cpos, try to CoW write_len clusters. Don't CoW |
3455 | * past max_cpos. This will stop when it runs into a hole or an | 3423 | * past max_cpos. This will stop when it runs into a hole or an |
3456 | * unrefcounted extent. | 3424 | * unrefcounted extent. |
3457 | */ | 3425 | */ |
3458 | static int ocfs2_refcount_cow_hunk(struct inode *inode, | 3426 | static int ocfs2_refcount_cow_hunk(struct inode *inode, |
3459 | struct file *file, | ||
3460 | struct buffer_head *di_bh, | 3427 | struct buffer_head *di_bh, |
3461 | u32 cpos, u32 write_len, u32 max_cpos) | 3428 | u32 cpos, u32 write_len, u32 max_cpos) |
3462 | { | 3429 | { |
@@ -3485,8 +3452,6 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode, | |||
3485 | 3452 | ||
3486 | BUG_ON(cow_len == 0); | 3453 | BUG_ON(cow_len == 0); |
3487 | 3454 | ||
3488 | ocfs2_readahead_for_cow(inode, file, cow_start, cow_len); | ||
3489 | |||
3490 | context = kzalloc(sizeof(struct ocfs2_cow_context), GFP_NOFS); | 3455 | context = kzalloc(sizeof(struct ocfs2_cow_context), GFP_NOFS); |
3491 | if (!context) { | 3456 | if (!context) { |
3492 | ret = -ENOMEM; | 3457 | ret = -ENOMEM; |
@@ -3508,7 +3473,6 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode, | |||
3508 | context->ref_root_bh = ref_root_bh; | 3473 | context->ref_root_bh = ref_root_bh; |
3509 | context->cow_duplicate_clusters = ocfs2_duplicate_clusters_by_page; | 3474 | context->cow_duplicate_clusters = ocfs2_duplicate_clusters_by_page; |
3510 | context->get_clusters = ocfs2_di_get_clusters; | 3475 | context->get_clusters = ocfs2_di_get_clusters; |
3511 | context->file = file; | ||
3512 | 3476 | ||
3513 | ocfs2_init_dinode_extent_tree(&context->data_et, | 3477 | ocfs2_init_dinode_extent_tree(&context->data_et, |
3514 | INODE_CACHE(inode), di_bh); | 3478 | INODE_CACHE(inode), di_bh); |
@@ -3537,7 +3501,6 @@ out: | |||
3537 | * clusters between cpos and cpos+write_len are safe to modify. | 3501 | * clusters between cpos and cpos+write_len are safe to modify. |
3538 | */ | 3502 | */ |
3539 | int ocfs2_refcount_cow(struct inode *inode, | 3503 | int ocfs2_refcount_cow(struct inode *inode, |
3540 | struct file *file, | ||
3541 | struct buffer_head *di_bh, | 3504 | struct buffer_head *di_bh, |
3542 | u32 cpos, u32 write_len, u32 max_cpos) | 3505 | u32 cpos, u32 write_len, u32 max_cpos) |
3543 | { | 3506 | { |
@@ -3557,7 +3520,7 @@ int ocfs2_refcount_cow(struct inode *inode, | |||
3557 | num_clusters = write_len; | 3520 | num_clusters = write_len; |
3558 | 3521 | ||
3559 | if (ext_flags & OCFS2_EXT_REFCOUNTED) { | 3522 | if (ext_flags & OCFS2_EXT_REFCOUNTED) { |
3560 | ret = ocfs2_refcount_cow_hunk(inode, file, di_bh, cpos, | 3523 | ret = ocfs2_refcount_cow_hunk(inode, di_bh, cpos, |
3561 | num_clusters, max_cpos); | 3524 | num_clusters, max_cpos); |
3562 | if (ret) { | 3525 | if (ret) { |
3563 | mlog_errno(ret); | 3526 | mlog_errno(ret); |
diff --git a/fs/ocfs2/refcounttree.h b/fs/ocfs2/refcounttree.h index 7754608c83a4..6422bbcdb525 100644 --- a/fs/ocfs2/refcounttree.h +++ b/fs/ocfs2/refcounttree.h | |||
@@ -53,7 +53,7 @@ int ocfs2_prepare_refcount_change_for_del(struct inode *inode, | |||
53 | int *credits, | 53 | int *credits, |
54 | int *ref_blocks); | 54 | int *ref_blocks); |
55 | int ocfs2_refcount_cow(struct inode *inode, | 55 | int ocfs2_refcount_cow(struct inode *inode, |
56 | struct file *filep, struct buffer_head *di_bh, | 56 | struct buffer_head *di_bh, |
57 | u32 cpos, u32 write_len, u32 max_cpos); | 57 | u32 cpos, u32 write_len, u32 max_cpos); |
58 | 58 | ||
59 | typedef int (ocfs2_post_refcount_func)(struct inode *inode, | 59 | typedef int (ocfs2_post_refcount_func)(struct inode *inode, |
@@ -85,11 +85,11 @@ int ocfs2_refcount_cow_xattr(struct inode *inode, | |||
85 | u32 cpos, u32 write_len, | 85 | u32 cpos, u32 write_len, |
86 | struct ocfs2_post_refcount *post); | 86 | struct ocfs2_post_refcount *post); |
87 | int ocfs2_duplicate_clusters_by_page(handle_t *handle, | 87 | int ocfs2_duplicate_clusters_by_page(handle_t *handle, |
88 | struct file *file, | 88 | struct inode *inode, |
89 | u32 cpos, u32 old_cluster, | 89 | u32 cpos, u32 old_cluster, |
90 | u32 new_cluster, u32 new_len); | 90 | u32 new_cluster, u32 new_len); |
91 | int ocfs2_duplicate_clusters_by_jbd(handle_t *handle, | 91 | int ocfs2_duplicate_clusters_by_jbd(handle_t *handle, |
92 | struct file *file, | 92 | struct inode *inode, |
93 | u32 cpos, u32 old_cluster, | 93 | u32 cpos, u32 old_cluster, |
94 | u32 new_cluster, u32 new_len); | 94 | u32 new_cluster, u32 new_len); |
95 | int ocfs2_cow_sync_writeback(struct super_block *sb, | 95 | int ocfs2_cow_sync_writeback(struct super_block *sb, |