https://github.com/torvalds/linux
Revision 914ee295af418e936ec20a08c1663eaabe4cd07a authored by Xin Zhong on 09 December 2010, 09:30:14 UTC, committed by Chris Mason on 10 December 2010, 21:29:10 UTC
This problem is found in meego testing: http://bugs.meego.com/show_bug.cgi?id=6672 A file in btrfs is mmaped and the mmaped buffer is passed to pwrite to write to the same page of the same file. In btrfs_file_aio_write(), the pages is locked by prepare_pages(). So when btrfs_copy_from_user() is called, page fault happens and the same page needs to be locked again in filemap_fault(). The fix is to move iov_iter_fault_in_readable() before prepage_pages() to make page fault happen before pages are locked. And also disable page fault in critical region in btrfs_copy_from_user(). Reviewed-by: Yan, Zheng<zheng.z.yan@intel.com> Signed-off-by: Zhong, Xin <xin.zhong@intel.com> Signed-off-by: Chris Mason <chris.mason@oracle.com>
1 parent f106e82
Tip revision: 914ee295af418e936ec20a08c1663eaabe4cd07a authored by Xin Zhong on 09 December 2010, 09:30:14 UTC
Btrfs: pwrite blocked when writing from the mmaped buffer of the same page
Btrfs: pwrite blocked when writing from the mmaped buffer of the same page
Tip revision: 914ee29
io.c
/*
* linux/fs/befs/io.c
*
* Copyright (C) 2001 Will Dyson <will_dyson@pobox.com
*
* Based on portions of file.c and inode.c
* by Makoto Kato (m_kato@ga2.so-net.ne.jp)
*
* Many thanks to Dominic Giampaolo, author of Practical File System
* Design with the Be File System, for such a helpful book.
*
*/
#include <linux/buffer_head.h>
#include "befs.h"
#include "io.h"
/*
* Converts befs notion of disk addr to a disk offset and uses
* linux kernel function sb_bread() to get the buffer containing
* the offset. -Will Dyson
*
*/
struct buffer_head *
befs_bread_iaddr(struct super_block *sb, befs_inode_addr iaddr)
{
struct buffer_head *bh = NULL;
befs_blocknr_t block = 0;
befs_sb_info *befs_sb = BEFS_SB(sb);
befs_debug(sb, "---> Enter befs_read_iaddr() "
"[%u, %hu, %hu]",
iaddr.allocation_group, iaddr.start, iaddr.len);
if (iaddr.allocation_group > befs_sb->num_ags) {
befs_error(sb, "BEFS: Invalid allocation group %u, max is %u",
iaddr.allocation_group, befs_sb->num_ags);
goto error;
}
block = iaddr2blockno(sb, &iaddr);
befs_debug(sb, "befs_read_iaddr: offset = %lu", block);
bh = sb_bread(sb, block);
if (bh == NULL) {
befs_error(sb, "Failed to read block %lu", block);
goto error;
}
befs_debug(sb, "<--- befs_read_iaddr()");
return bh;
error:
befs_debug(sb, "<--- befs_read_iaddr() ERROR");
return NULL;
}
struct buffer_head *
befs_bread(struct super_block *sb, befs_blocknr_t block)
{
struct buffer_head *bh = NULL;
befs_debug(sb, "---> Enter befs_read() %Lu", block);
bh = sb_bread(sb, block);
if (bh == NULL) {
befs_error(sb, "Failed to read block %lu", block);
goto error;
}
befs_debug(sb, "<--- befs_read()");
return bh;
error:
befs_debug(sb, "<--- befs_read() ERROR");
return NULL;
}
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...