mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 20:22:09 +00:00
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>
This commit is contained in:
parent
6115ea2884
commit
c7dd3392ad
@ -1757,7 +1757,7 @@ try_again:
|
|||||||
goto out;
|
goto out;
|
||||||
} else if (ret == 1) {
|
} else if (ret == 1) {
|
||||||
clusters_need = wc->w_clen;
|
clusters_need = wc->w_clen;
|
||||||
ret = ocfs2_refcount_cow(inode, filp, di_bh,
|
ret = ocfs2_refcount_cow(inode, di_bh,
|
||||||
wc->w_cpos, wc->w_clen, UINT_MAX);
|
wc->w_cpos, wc->w_clen, UINT_MAX);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
mlog_errno(ret);
|
mlog_errno(ret);
|
||||||
|
@ -370,7 +370,7 @@ static int ocfs2_cow_file_pos(struct inode *inode,
|
|||||||
if (!(ext_flags & OCFS2_EXT_REFCOUNTED))
|
if (!(ext_flags & OCFS2_EXT_REFCOUNTED))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
return ocfs2_refcount_cow(inode, NULL, fe_bh, cpos, 1, cpos+1);
|
return ocfs2_refcount_cow(inode, fe_bh, cpos, 1, cpos+1);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return status;
|
return status;
|
||||||
@ -899,7 +899,7 @@ static int ocfs2_zero_extend_get_range(struct inode *inode,
|
|||||||
zero_clusters = last_cpos - zero_cpos;
|
zero_clusters = last_cpos - zero_cpos;
|
||||||
|
|
||||||
if (needs_cow) {
|
if (needs_cow) {
|
||||||
rc = ocfs2_refcount_cow(inode, NULL, di_bh, zero_cpos,
|
rc = ocfs2_refcount_cow(inode, di_bh, zero_cpos,
|
||||||
zero_clusters, UINT_MAX);
|
zero_clusters, UINT_MAX);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
mlog_errno(rc);
|
mlog_errno(rc);
|
||||||
@ -2078,7 +2078,7 @@ static int ocfs2_prepare_inode_for_refcount(struct inode *inode,
|
|||||||
|
|
||||||
*meta_level = 1;
|
*meta_level = 1;
|
||||||
|
|
||||||
ret = ocfs2_refcount_cow(inode, file, di_bh, cpos, clusters, UINT_MAX);
|
ret = ocfs2_refcount_cow(inode, di_bh, cpos, clusters, UINT_MAX);
|
||||||
if (ret)
|
if (ret)
|
||||||
mlog_errno(ret);
|
mlog_errno(ret);
|
||||||
out:
|
out:
|
||||||
|
@ -69,7 +69,7 @@ static int __ocfs2_move_extent(handle_t *handle,
|
|||||||
u64 ino = ocfs2_metadata_cache_owner(context->et.et_ci);
|
u64 ino = ocfs2_metadata_cache_owner(context->et.et_ci);
|
||||||
u64 old_blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cpos);
|
u64 old_blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cpos);
|
||||||
|
|
||||||
ret = ocfs2_duplicate_clusters_by_page(handle, context->file, cpos,
|
ret = ocfs2_duplicate_clusters_by_page(handle, inode, cpos,
|
||||||
p_cpos, new_p_cpos, len);
|
p_cpos, new_p_cpos, len);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
mlog_errno(ret);
|
mlog_errno(ret);
|
||||||
|
@ -49,7 +49,6 @@
|
|||||||
|
|
||||||
struct ocfs2_cow_context {
|
struct ocfs2_cow_context {
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct file *file;
|
|
||||||
u32 cow_start;
|
u32 cow_start;
|
||||||
u32 cow_len;
|
u32 cow_len;
|
||||||
struct ocfs2_extent_tree data_et;
|
struct ocfs2_extent_tree data_et;
|
||||||
@ -66,7 +65,7 @@ struct ocfs2_cow_context {
|
|||||||
u32 *num_clusters,
|
u32 *num_clusters,
|
||||||
unsigned int *extent_flags);
|
unsigned int *extent_flags);
|
||||||
int (*cow_duplicate_clusters)(handle_t *handle,
|
int (*cow_duplicate_clusters)(handle_t *handle,
|
||||||
struct file *file,
|
struct inode *inode,
|
||||||
u32 cpos, u32 old_cluster,
|
u32 cpos, u32 old_cluster,
|
||||||
u32 new_cluster, u32 new_len);
|
u32 new_cluster, u32 new_len);
|
||||||
};
|
};
|
||||||
@ -2922,14 +2921,12 @@ static int ocfs2_clear_cow_buffer(handle_t *handle, struct buffer_head *bh)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ocfs2_duplicate_clusters_by_page(handle_t *handle,
|
int ocfs2_duplicate_clusters_by_page(handle_t *handle,
|
||||||
struct file *file,
|
struct inode *inode,
|
||||||
u32 cpos, u32 old_cluster,
|
u32 cpos, u32 old_cluster,
|
||||||
u32 new_cluster, u32 new_len)
|
u32 new_cluster, u32 new_len)
|
||||||
{
|
{
|
||||||
int ret = 0, partial;
|
int ret = 0, partial;
|
||||||
struct inode *inode = file_inode(file);
|
struct super_block *sb = inode->i_sb;
|
||||||
struct ocfs2_caching_info *ci = INODE_CACHE(inode);
|
|
||||||
struct super_block *sb = ocfs2_metadata_cache_get_super(ci);
|
|
||||||
u64 new_block = ocfs2_clusters_to_blocks(sb, new_cluster);
|
u64 new_block = ocfs2_clusters_to_blocks(sb, new_cluster);
|
||||||
struct page *page;
|
struct page *page;
|
||||||
pgoff_t page_index;
|
pgoff_t page_index;
|
||||||
@ -2978,13 +2975,6 @@ int ocfs2_duplicate_clusters_by_page(handle_t *handle,
|
|||||||
if (PAGE_CACHE_SIZE <= OCFS2_SB(sb)->s_clustersize)
|
if (PAGE_CACHE_SIZE <= OCFS2_SB(sb)->s_clustersize)
|
||||||
BUG_ON(PageDirty(page));
|
BUG_ON(PageDirty(page));
|
||||||
|
|
||||||
if (PageReadahead(page)) {
|
|
||||||
page_cache_async_readahead(mapping,
|
|
||||||
&file->f_ra, file,
|
|
||||||
page, page_index,
|
|
||||||
readahead_pages);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PageUptodate(page)) {
|
if (!PageUptodate(page)) {
|
||||||
ret = block_read_full_page(page, ocfs2_get_block);
|
ret = block_read_full_page(page, ocfs2_get_block);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@ -3004,7 +2994,8 @@ int ocfs2_duplicate_clusters_by_page(handle_t *handle,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ocfs2_map_and_dirty_page(inode, handle, from, to,
|
ocfs2_map_and_dirty_page(inode,
|
||||||
|
handle, from, to,
|
||||||
page, 0, &new_block);
|
page, 0, &new_block);
|
||||||
mark_page_accessed(page);
|
mark_page_accessed(page);
|
||||||
unlock:
|
unlock:
|
||||||
@ -3020,12 +3011,11 @@ unlock:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ocfs2_duplicate_clusters_by_jbd(handle_t *handle,
|
int ocfs2_duplicate_clusters_by_jbd(handle_t *handle,
|
||||||
struct file *file,
|
struct inode *inode,
|
||||||
u32 cpos, u32 old_cluster,
|
u32 cpos, u32 old_cluster,
|
||||||
u32 new_cluster, u32 new_len)
|
u32 new_cluster, u32 new_len)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct inode *inode = file_inode(file);
|
|
||||||
struct super_block *sb = inode->i_sb;
|
struct super_block *sb = inode->i_sb;
|
||||||
struct ocfs2_caching_info *ci = INODE_CACHE(inode);
|
struct ocfs2_caching_info *ci = INODE_CACHE(inode);
|
||||||
int i, blocks = ocfs2_clusters_to_blocks(sb, new_len);
|
int i, blocks = ocfs2_clusters_to_blocks(sb, new_len);
|
||||||
@ -3150,7 +3140,7 @@ static int ocfs2_replace_clusters(handle_t *handle,
|
|||||||
|
|
||||||
/*If the old clusters is unwritten, no need to duplicate. */
|
/*If the old clusters is unwritten, no need to duplicate. */
|
||||||
if (!(ext_flags & OCFS2_EXT_UNWRITTEN)) {
|
if (!(ext_flags & OCFS2_EXT_UNWRITTEN)) {
|
||||||
ret = context->cow_duplicate_clusters(handle, context->file,
|
ret = context->cow_duplicate_clusters(handle, context->inode,
|
||||||
cpos, old, new, len);
|
cpos, old, new, len);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
mlog_errno(ret);
|
mlog_errno(ret);
|
||||||
@ -3428,35 +3418,12 @@ static int ocfs2_replace_cow(struct ocfs2_cow_context *context)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ocfs2_readahead_for_cow(struct inode *inode,
|
|
||||||
struct file *file,
|
|
||||||
u32 start, u32 len)
|
|
||||||
{
|
|
||||||
struct address_space *mapping;
|
|
||||||
pgoff_t index;
|
|
||||||
unsigned long num_pages;
|
|
||||||
int cs_bits = OCFS2_SB(inode->i_sb)->s_clustersize_bits;
|
|
||||||
|
|
||||||
if (!file)
|
|
||||||
return;
|
|
||||||
|
|
||||||
mapping = file->f_mapping;
|
|
||||||
num_pages = (len << cs_bits) >> PAGE_CACHE_SHIFT;
|
|
||||||
if (!num_pages)
|
|
||||||
num_pages = 1;
|
|
||||||
|
|
||||||
index = ((loff_t)start << cs_bits) >> PAGE_CACHE_SHIFT;
|
|
||||||
page_cache_sync_readahead(mapping, &file->f_ra, file,
|
|
||||||
index, num_pages);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Starting at cpos, try to CoW write_len clusters. Don't CoW
|
* Starting at cpos, try to CoW write_len clusters. Don't CoW
|
||||||
* past max_cpos. This will stop when it runs into a hole or an
|
* past max_cpos. This will stop when it runs into a hole or an
|
||||||
* unrefcounted extent.
|
* unrefcounted extent.
|
||||||
*/
|
*/
|
||||||
static int ocfs2_refcount_cow_hunk(struct inode *inode,
|
static int ocfs2_refcount_cow_hunk(struct inode *inode,
|
||||||
struct file *file,
|
|
||||||
struct buffer_head *di_bh,
|
struct buffer_head *di_bh,
|
||||||
u32 cpos, u32 write_len, u32 max_cpos)
|
u32 cpos, u32 write_len, u32 max_cpos)
|
||||||
{
|
{
|
||||||
@ -3485,8 +3452,6 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode,
|
|||||||
|
|
||||||
BUG_ON(cow_len == 0);
|
BUG_ON(cow_len == 0);
|
||||||
|
|
||||||
ocfs2_readahead_for_cow(inode, file, cow_start, cow_len);
|
|
||||||
|
|
||||||
context = kzalloc(sizeof(struct ocfs2_cow_context), GFP_NOFS);
|
context = kzalloc(sizeof(struct ocfs2_cow_context), GFP_NOFS);
|
||||||
if (!context) {
|
if (!context) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
@ -3508,7 +3473,6 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode,
|
|||||||
context->ref_root_bh = ref_root_bh;
|
context->ref_root_bh = ref_root_bh;
|
||||||
context->cow_duplicate_clusters = ocfs2_duplicate_clusters_by_page;
|
context->cow_duplicate_clusters = ocfs2_duplicate_clusters_by_page;
|
||||||
context->get_clusters = ocfs2_di_get_clusters;
|
context->get_clusters = ocfs2_di_get_clusters;
|
||||||
context->file = file;
|
|
||||||
|
|
||||||
ocfs2_init_dinode_extent_tree(&context->data_et,
|
ocfs2_init_dinode_extent_tree(&context->data_et,
|
||||||
INODE_CACHE(inode), di_bh);
|
INODE_CACHE(inode), di_bh);
|
||||||
@ -3537,7 +3501,6 @@ out:
|
|||||||
* clusters between cpos and cpos+write_len are safe to modify.
|
* clusters between cpos and cpos+write_len are safe to modify.
|
||||||
*/
|
*/
|
||||||
int ocfs2_refcount_cow(struct inode *inode,
|
int ocfs2_refcount_cow(struct inode *inode,
|
||||||
struct file *file,
|
|
||||||
struct buffer_head *di_bh,
|
struct buffer_head *di_bh,
|
||||||
u32 cpos, u32 write_len, u32 max_cpos)
|
u32 cpos, u32 write_len, u32 max_cpos)
|
||||||
{
|
{
|
||||||
@ -3557,7 +3520,7 @@ int ocfs2_refcount_cow(struct inode *inode,
|
|||||||
num_clusters = write_len;
|
num_clusters = write_len;
|
||||||
|
|
||||||
if (ext_flags & OCFS2_EXT_REFCOUNTED) {
|
if (ext_flags & OCFS2_EXT_REFCOUNTED) {
|
||||||
ret = ocfs2_refcount_cow_hunk(inode, file, di_bh, cpos,
|
ret = ocfs2_refcount_cow_hunk(inode, di_bh, cpos,
|
||||||
num_clusters, max_cpos);
|
num_clusters, max_cpos);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
mlog_errno(ret);
|
mlog_errno(ret);
|
||||||
|
@ -53,7 +53,7 @@ int ocfs2_prepare_refcount_change_for_del(struct inode *inode,
|
|||||||
int *credits,
|
int *credits,
|
||||||
int *ref_blocks);
|
int *ref_blocks);
|
||||||
int ocfs2_refcount_cow(struct inode *inode,
|
int ocfs2_refcount_cow(struct inode *inode,
|
||||||
struct file *filep, struct buffer_head *di_bh,
|
struct buffer_head *di_bh,
|
||||||
u32 cpos, u32 write_len, u32 max_cpos);
|
u32 cpos, u32 write_len, u32 max_cpos);
|
||||||
|
|
||||||
typedef int (ocfs2_post_refcount_func)(struct inode *inode,
|
typedef int (ocfs2_post_refcount_func)(struct inode *inode,
|
||||||
@ -85,11 +85,11 @@ int ocfs2_refcount_cow_xattr(struct inode *inode,
|
|||||||
u32 cpos, u32 write_len,
|
u32 cpos, u32 write_len,
|
||||||
struct ocfs2_post_refcount *post);
|
struct ocfs2_post_refcount *post);
|
||||||
int ocfs2_duplicate_clusters_by_page(handle_t *handle,
|
int ocfs2_duplicate_clusters_by_page(handle_t *handle,
|
||||||
struct file *file,
|
struct inode *inode,
|
||||||
u32 cpos, u32 old_cluster,
|
u32 cpos, u32 old_cluster,
|
||||||
u32 new_cluster, u32 new_len);
|
u32 new_cluster, u32 new_len);
|
||||||
int ocfs2_duplicate_clusters_by_jbd(handle_t *handle,
|
int ocfs2_duplicate_clusters_by_jbd(handle_t *handle,
|
||||||
struct file *file,
|
struct inode *inode,
|
||||||
u32 cpos, u32 old_cluster,
|
u32 cpos, u32 old_cluster,
|
||||||
u32 new_cluster, u32 new_len);
|
u32 new_cluster, u32 new_len);
|
||||||
int ocfs2_cow_sync_writeback(struct super_block *sb,
|
int ocfs2_cow_sync_writeback(struct super_block *sb,
|
||||||
|
Loading…
Reference in New Issue
Block a user