2010-10-28 09:30:10 +08:00
|
|
|
/*
|
|
|
|
* linux/fs/ext4/page-io.c
|
|
|
|
*
|
|
|
|
* This contains the new page_io functions for ext4
|
|
|
|
*
|
|
|
|
* Written by Theodore Ts'o, 2010.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <linux/time.h>
|
|
|
|
#include <linux/jbd2.h>
|
|
|
|
#include <linux/highuid.h>
|
|
|
|
#include <linux/pagemap.h>
|
|
|
|
#include <linux/quotaops.h>
|
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/buffer_head.h>
|
|
|
|
#include <linux/writeback.h>
|
|
|
|
#include <linux/pagevec.h>
|
|
|
|
#include <linux/mpage.h>
|
|
|
|
#include <linux/namei.h>
|
2013-05-08 07:19:08 +08:00
|
|
|
#include <linux/aio.h>
|
2010-10-28 09:30:10 +08:00
|
|
|
#include <linux/uio.h>
|
|
|
|
#include <linux/bio.h>
|
|
|
|
#include <linux/workqueue.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/slab.h>
|
2013-01-28 22:32:54 +08:00
|
|
|
#include <linux/mm.h>
|
2010-10-28 09:30:10 +08:00
|
|
|
|
|
|
|
#include "ext4_jbd2.h"
|
|
|
|
#include "xattr.h"
|
|
|
|
#include "acl.h"
|
|
|
|
|
2013-04-12 11:48:32 +08:00
|
|
|
static struct kmem_cache *io_end_cachep;
|
2010-10-28 09:30:10 +08:00
|
|
|
|
2010-10-28 09:30:14 +08:00
|
|
|
int __init ext4_init_pageio(void)
|
2010-10-28 09:30:10 +08:00
|
|
|
{
|
|
|
|
io_end_cachep = KMEM_CACHE(ext4_io_end, SLAB_RECLAIM_ACCOUNT);
|
2013-04-12 11:48:32 +08:00
|
|
|
if (io_end_cachep == NULL)
|
2010-10-28 09:30:10 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-10-28 09:30:14 +08:00
|
|
|
void ext4_exit_pageio(void)
|
2010-10-28 09:30:10 +08:00
|
|
|
{
|
|
|
|
kmem_cache_destroy(io_end_cachep);
|
|
|
|
}
|
|
|
|
|
ext4: fix ext4_evict_inode() racing against workqueue processing code
Commit 84c17543ab56 (ext4: move work from io_end to inode) triggered a
regression when running xfstest #270 when the file system is mounted
with dioread_nolock.
The problem is that after ext4_evict_inode() calls ext4_ioend_wait(),
this guarantees that last io_end structure has been freed, but it does
not guarantee that the workqueue structure, which was moved into the
inode by commit 84c17543ab56, is actually finished. Once
ext4_flush_completed_IO() calls ext4_free_io_end() on CPU #1, this
will allow ext4_ioend_wait() to return on CPU #2, at which point the
evict_inode() codepath can race against the workqueue code on CPU #1
accessing EXT4_I(inode)->i_unwritten_work to find the next item of
work to do.
Fix this by calling cancel_work_sync() in ext4_ioend_wait(), which
will be renamed ext4_ioend_shutdown(), since it is only used by
ext4_evict_inode(). Also, move the call to ext4_ioend_shutdown()
until after truncate_inode_pages() and filemap_write_and_wait() are
called, to make sure all dirty pages have been written back and
flushed from the page cache first.
BUG: unable to handle kernel NULL pointer dereference at (null)
IP: [<c01dda6a>] cwq_activate_delayed_work+0x3b/0x7e
*pdpt = 0000000030bc3001 *pde = 0000000000000000
Oops: 0000 [#1] SMP DEBUG_PAGEALLOC
Modules linked in:
Pid: 6, comm: kworker/u:0 Not tainted 3.8.0-rc3-00013-g84c1754-dirty #91 Bochs Bochs
EIP: 0060:[<c01dda6a>] EFLAGS: 00010046 CPU: 0
EIP is at cwq_activate_delayed_work+0x3b/0x7e
EAX: 00000000 EBX: 00000000 ECX: f505fe54 EDX: 00000000
ESI: ed5b697c EDI: 00000006 EBP: f64b7e8c ESP: f64b7e84
DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068
CR0: 8005003b CR2: 00000000 CR3: 30bc2000 CR4: 000006f0
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: ffff0ff0 DR7: 00000400
Process kworker/u:0 (pid: 6, ti=f64b6000 task=f64b4160 task.ti=f64b6000)
Stack:
f505fe00 00000006 f64b7e9c c01de3d7 f6435540 00000003 f64b7efc c01def1d
f6435540 00000002 00000000 0000008a c16d0808 c040a10b c16d07d8 c16d08b0
f505fe00 c16d0780 00000000 00000000 ee153df4 c1ce4a30 c17d0e30 00000000
Call Trace:
[<c01de3d7>] cwq_dec_nr_in_flight+0x71/0xfb
[<c01def1d>] process_one_work+0x5d8/0x637
[<c040a10b>] ? ext4_end_bio+0x300/0x300
[<c01e3105>] worker_thread+0x249/0x3ef
[<c01ea317>] kthread+0xd8/0xeb
[<c01e2ebc>] ? manage_workers+0x4bb/0x4bb
[<c023a370>] ? trace_hardirqs_on+0x27/0x37
[<c0f1b4b7>] ret_from_kernel_thread+0x1b/0x28
[<c01ea23f>] ? __init_kthread_worker+0x71/0x71
Code: 01 83 15 ac ff 6c c1 00 31 db 89 c6 8b 00 a8 04 74 12 89 c3 30 db 83 05 b0 ff 6c c1 01 83 15 b4 ff 6c c1 00 89 f0 e8 42 ff ff ff <8b> 13 89 f0 83 05 b8 ff 6c c1
6c c1 00 31 c9 83
EIP: [<c01dda6a>] cwq_activate_delayed_work+0x3b/0x7e SS:ESP 0068:f64b7e84
CR2: 0000000000000000
---[ end trace a1923229da53d8a4 ]---
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Cc: Jan Kara <jack@suse.cz>
2013-03-20 21:39:42 +08:00
|
|
|
/*
|
|
|
|
* This function is called by ext4_evict_inode() to make sure there is
|
|
|
|
* no more pending I/O completion work left to do.
|
|
|
|
*/
|
|
|
|
void ext4_ioend_shutdown(struct inode *inode)
|
2010-11-09 02:43:33 +08:00
|
|
|
{
|
ext4: serialize unaligned asynchronous DIO
ext4 has a data corruption case when doing non-block-aligned
asynchronous direct IO into a sparse file, as demonstrated
by xfstest 240.
The root cause is that while ext4 preallocates space in the
hole, mappings of that space still look "new" and
dio_zero_block() will zero out the unwritten portions. When
more than one AIO thread is going, they both find this "new"
block and race to zero out their portion; this is uncoordinated
and causes data corruption.
Dave Chinner fixed this for xfs by simply serializing all
unaligned asynchronous direct IO. I've done the same here.
The difference is that we only wait on conversions, not all IO.
This is a very big hammer, and I'm not very pleased with
stuffing this into ext4_file_write(). But since ext4 is
DIO_LOCKING, we need to serialize it at this high level.
I tried to move this into ext4_ext_direct_IO, but by then
we have the i_mutex already, and we will wait on the
work queue to do conversions - which must also take the
i_mutex. So that won't work.
This was originally exposed by qemu-kvm installing to
a raw disk image with a normal sector-63 alignment. I've
tested a backport of this patch with qemu, and it does
avoid the corruption. It is also quite a lot slower
(14 min for package installs, vs. 8 min for well-aligned)
but I'll take slow correctness over fast corruption any day.
Mingming suggested that we can track outstanding
conversions, and wait on those so that non-sparse
files won't be affected, and I've implemented that here;
unaligned AIO to nonsparse files won't take a perf hit.
[tytso@mit.edu: Keep the mutex as a hashed array instead
of bloating the ext4 inode]
[tytso@mit.edu: Fix up namespace issues so that global
variables are protected with an "ext4_" prefix.]
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2011-02-12 21:17:34 +08:00
|
|
|
wait_queue_head_t *wq = ext4_ioend_wq(inode);
|
2010-11-09 02:43:33 +08:00
|
|
|
|
|
|
|
wait_event(*wq, (atomic_read(&EXT4_I(inode)->i_ioend_count) == 0));
|
ext4: fix ext4_evict_inode() racing against workqueue processing code
Commit 84c17543ab56 (ext4: move work from io_end to inode) triggered a
regression when running xfstest #270 when the file system is mounted
with dioread_nolock.
The problem is that after ext4_evict_inode() calls ext4_ioend_wait(),
this guarantees that last io_end structure has been freed, but it does
not guarantee that the workqueue structure, which was moved into the
inode by commit 84c17543ab56, is actually finished. Once
ext4_flush_completed_IO() calls ext4_free_io_end() on CPU #1, this
will allow ext4_ioend_wait() to return on CPU #2, at which point the
evict_inode() codepath can race against the workqueue code on CPU #1
accessing EXT4_I(inode)->i_unwritten_work to find the next item of
work to do.
Fix this by calling cancel_work_sync() in ext4_ioend_wait(), which
will be renamed ext4_ioend_shutdown(), since it is only used by
ext4_evict_inode(). Also, move the call to ext4_ioend_shutdown()
until after truncate_inode_pages() and filemap_write_and_wait() are
called, to make sure all dirty pages have been written back and
flushed from the page cache first.
BUG: unable to handle kernel NULL pointer dereference at (null)
IP: [<c01dda6a>] cwq_activate_delayed_work+0x3b/0x7e
*pdpt = 0000000030bc3001 *pde = 0000000000000000
Oops: 0000 [#1] SMP DEBUG_PAGEALLOC
Modules linked in:
Pid: 6, comm: kworker/u:0 Not tainted 3.8.0-rc3-00013-g84c1754-dirty #91 Bochs Bochs
EIP: 0060:[<c01dda6a>] EFLAGS: 00010046 CPU: 0
EIP is at cwq_activate_delayed_work+0x3b/0x7e
EAX: 00000000 EBX: 00000000 ECX: f505fe54 EDX: 00000000
ESI: ed5b697c EDI: 00000006 EBP: f64b7e8c ESP: f64b7e84
DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068
CR0: 8005003b CR2: 00000000 CR3: 30bc2000 CR4: 000006f0
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: ffff0ff0 DR7: 00000400
Process kworker/u:0 (pid: 6, ti=f64b6000 task=f64b4160 task.ti=f64b6000)
Stack:
f505fe00 00000006 f64b7e9c c01de3d7 f6435540 00000003 f64b7efc c01def1d
f6435540 00000002 00000000 0000008a c16d0808 c040a10b c16d07d8 c16d08b0
f505fe00 c16d0780 00000000 00000000 ee153df4 c1ce4a30 c17d0e30 00000000
Call Trace:
[<c01de3d7>] cwq_dec_nr_in_flight+0x71/0xfb
[<c01def1d>] process_one_work+0x5d8/0x637
[<c040a10b>] ? ext4_end_bio+0x300/0x300
[<c01e3105>] worker_thread+0x249/0x3ef
[<c01ea317>] kthread+0xd8/0xeb
[<c01e2ebc>] ? manage_workers+0x4bb/0x4bb
[<c023a370>] ? trace_hardirqs_on+0x27/0x37
[<c0f1b4b7>] ret_from_kernel_thread+0x1b/0x28
[<c01ea23f>] ? __init_kthread_worker+0x71/0x71
Code: 01 83 15 ac ff 6c c1 00 31 db 89 c6 8b 00 a8 04 74 12 89 c3 30 db 83 05 b0 ff 6c c1 01 83 15 b4 ff 6c c1 00 89 f0 e8 42 ff ff ff <8b> 13 89 f0 83 05 b8 ff 6c c1
6c c1 00 31 c9 83
EIP: [<c01dda6a>] cwq_activate_delayed_work+0x3b/0x7e SS:ESP 0068:f64b7e84
CR2: 0000000000000000
---[ end trace a1923229da53d8a4 ]---
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Cc: Jan Kara <jack@suse.cz>
2013-03-20 21:39:42 +08:00
|
|
|
/*
|
|
|
|
* We need to make sure the work structure is finished being
|
|
|
|
* used before we let the inode get destroyed.
|
|
|
|
*/
|
|
|
|
if (work_pending(&EXT4_I(inode)->i_unwritten_work))
|
|
|
|
cancel_work_sync(&EXT4_I(inode)->i_unwritten_work);
|
2010-11-09 02:43:33 +08:00
|
|
|
}
|
|
|
|
|
2013-05-12 07:07:42 +08:00
|
|
|
void ext4_free_io_end(ext4_io_end_t *io)
|
2010-10-28 09:30:10 +08:00
|
|
|
{
|
2013-05-12 07:07:42 +08:00
|
|
|
BUG_ON(!io);
|
|
|
|
BUG_ON(!list_empty(&io->list));
|
|
|
|
BUG_ON(io->flag & EXT4_IO_END_UNWRITTEN);
|
2012-09-29 11:36:25 +08:00
|
|
|
|
2013-05-12 07:07:42 +08:00
|
|
|
if (atomic_dec_and_test(&EXT4_I(io->inode)->i_ioend_count))
|
|
|
|
wake_up_all(ext4_ioend_wq(io->inode));
|
|
|
|
kmem_cache_free(io_end_cachep, io);
|
2010-10-28 09:30:10 +08:00
|
|
|
}
|
|
|
|
|
2012-09-29 12:14:55 +08:00
|
|
|
/* check a range of space and convert unwritten extents to written. */
|
|
|
|
static int ext4_end_io(ext4_io_end_t *io)
|
2010-10-28 09:30:10 +08:00
|
|
|
{
|
|
|
|
struct inode *inode = io->inode;
|
|
|
|
loff_t offset = io->offset;
|
|
|
|
ssize_t size = io->size;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
ext4_debug("ext4_end_io_nolock: io 0x%p from inode %lu,list->next 0x%p,"
|
|
|
|
"list->prev 0x%p\n",
|
|
|
|
io, inode->i_ino, io->list.next, io->list.prev);
|
|
|
|
|
|
|
|
ret = ext4_convert_unwritten_extents(inode, offset, size);
|
|
|
|
if (ret < 0) {
|
2011-10-31 22:56:32 +08:00
|
|
|
ext4_msg(inode->i_sb, KERN_EMERG,
|
|
|
|
"failed to convert unwritten extents to written "
|
|
|
|
"extents -- potential data loss! "
|
|
|
|
"(inode %lu, offset %llu, size %zd, error %d)",
|
|
|
|
inode->i_ino, offset, size, ret);
|
2010-10-28 09:30:10 +08:00
|
|
|
}
|
2013-05-12 07:07:42 +08:00
|
|
|
/* Wake up anyone waiting on unwritten extent conversion */
|
|
|
|
if (atomic_dec_and_test(&EXT4_I(inode)->i_unwritten))
|
|
|
|
wake_up_all(ext4_ioend_wq(inode));
|
|
|
|
if (io->flag & EXT4_IO_END_DIRECT)
|
|
|
|
inode_dio_done(inode);
|
|
|
|
if (io->iocb)
|
|
|
|
aio_complete(io->iocb, io->result, 0);
|
2010-10-28 09:30:10 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-09-29 12:14:55 +08:00
|
|
|
static void dump_completed_IO(struct inode *inode)
|
|
|
|
{
|
|
|
|
#ifdef EXT4FS_DEBUG
|
|
|
|
struct list_head *cur, *before, *after;
|
|
|
|
ext4_io_end_t *io, *io0, *io1;
|
|
|
|
|
|
|
|
if (list_empty(&EXT4_I(inode)->i_completed_io_list)) {
|
|
|
|
ext4_debug("inode %lu completed_io list is empty\n",
|
|
|
|
inode->i_ino);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ext4_debug("Dump inode %lu completed_io list\n", inode->i_ino);
|
|
|
|
list_for_each_entry(io, &EXT4_I(inode)->i_completed_io_list, list) {
|
|
|
|
cur = &io->list;
|
|
|
|
before = cur->prev;
|
|
|
|
io0 = container_of(before, ext4_io_end_t, list);
|
|
|
|
after = cur->next;
|
|
|
|
io1 = container_of(after, ext4_io_end_t, list);
|
|
|
|
|
|
|
|
ext4_debug("io 0x%p from inode %lu,prev 0x%p,next 0x%p\n",
|
|
|
|
io, inode->i_ino, io0, io1);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add the io_end to per-inode completed end_io list. */
|
2013-05-12 07:07:42 +08:00
|
|
|
void ext4_add_complete_io(ext4_io_end_t *io_end)
|
2010-10-28 09:30:10 +08:00
|
|
|
{
|
2012-09-29 12:14:55 +08:00
|
|
|
struct ext4_inode_info *ei = EXT4_I(io_end->inode);
|
|
|
|
struct workqueue_struct *wq;
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
BUG_ON(!(io_end->flag & EXT4_IO_END_UNWRITTEN));
|
|
|
|
wq = EXT4_SB(io_end->inode->i_sb)->dio_unwritten_wq;
|
2010-10-28 09:30:10 +08:00
|
|
|
|
2011-10-31 06:26:08 +08:00
|
|
|
spin_lock_irqsave(&ei->i_completed_io_lock, flags);
|
2013-01-28 22:43:46 +08:00
|
|
|
if (list_empty(&ei->i_completed_io_list))
|
|
|
|
queue_work(wq, &ei->i_unwritten_work);
|
2012-09-29 12:14:55 +08:00
|
|
|
list_add_tail(&io_end->list, &ei->i_completed_io_list);
|
|
|
|
spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
|
|
|
|
}
|
2011-10-31 06:26:08 +08:00
|
|
|
|
2013-01-28 22:43:46 +08:00
|
|
|
static int ext4_do_flush_completed_IO(struct inode *inode)
|
2012-09-29 12:14:55 +08:00
|
|
|
{
|
|
|
|
ext4_io_end_t *io;
|
2013-01-28 22:49:15 +08:00
|
|
|
struct list_head unwritten;
|
2012-09-29 12:14:55 +08:00
|
|
|
unsigned long flags;
|
|
|
|
struct ext4_inode_info *ei = EXT4_I(inode);
|
|
|
|
int err, ret = 0;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&ei->i_completed_io_lock, flags);
|
|
|
|
dump_completed_IO(inode);
|
|
|
|
list_replace_init(&ei->i_completed_io_list, &unwritten);
|
|
|
|
spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
|
|
|
|
|
|
|
|
while (!list_empty(&unwritten)) {
|
|
|
|
io = list_entry(unwritten.next, ext4_io_end_t, list);
|
|
|
|
BUG_ON(!(io->flag & EXT4_IO_END_UNWRITTEN));
|
|
|
|
list_del_init(&io->list);
|
|
|
|
|
|
|
|
err = ext4_end_io(io);
|
|
|
|
if (unlikely(!ret && err))
|
|
|
|
ret = err;
|
2013-05-12 07:07:42 +08:00
|
|
|
io->flag &= ~EXT4_IO_END_UNWRITTEN;
|
|
|
|
ext4_free_io_end(io);
|
2012-09-29 12:14:55 +08:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* work on completed aio dio IO, to convert unwritten extents to extents
|
|
|
|
*/
|
2013-01-28 22:43:46 +08:00
|
|
|
void ext4_end_io_work(struct work_struct *work)
|
2012-09-29 12:14:55 +08:00
|
|
|
{
|
2013-01-28 22:43:46 +08:00
|
|
|
struct ext4_inode_info *ei = container_of(work, struct ext4_inode_info,
|
|
|
|
i_unwritten_work);
|
|
|
|
ext4_do_flush_completed_IO(&ei->vfs_inode);
|
2012-09-29 12:14:55 +08:00
|
|
|
}
|
|
|
|
|
2012-10-05 23:31:55 +08:00
|
|
|
int ext4_flush_unwritten_io(struct inode *inode)
|
2012-09-29 12:14:55 +08:00
|
|
|
{
|
2012-10-05 23:31:55 +08:00
|
|
|
int ret;
|
|
|
|
WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex) &&
|
|
|
|
!(inode->i_state & I_FREEING));
|
2013-01-28 22:43:46 +08:00
|
|
|
ret = ext4_do_flush_completed_IO(inode);
|
2012-10-05 23:31:55 +08:00
|
|
|
ext4_unwritten_wait(inode);
|
|
|
|
return ret;
|
2010-10-28 09:30:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags)
|
|
|
|
{
|
2010-12-20 10:41:55 +08:00
|
|
|
ext4_io_end_t *io = kmem_cache_zalloc(io_end_cachep, flags);
|
2010-10-28 09:30:10 +08:00
|
|
|
if (io) {
|
2010-11-09 02:43:33 +08:00
|
|
|
atomic_inc(&EXT4_I(inode)->i_ioend_count);
|
|
|
|
io->inode = inode;
|
2010-10-28 09:30:10 +08:00
|
|
|
INIT_LIST_HEAD(&io->list);
|
|
|
|
}
|
|
|
|
return io;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Print an buffer I/O error compatible with the fs/buffer.c. This
|
|
|
|
* provides compatibility with dmesg scrapers that look for a specific
|
|
|
|
* buffer I/O error message. We really need a unified error reporting
|
|
|
|
* structure to userspace ala Digital Unix's uerf system, but it's
|
|
|
|
* probably not going to happen in my lifetime, due to LKML politics...
|
|
|
|
*/
|
|
|
|
static void buffer_io_error(struct buffer_head *bh)
|
|
|
|
{
|
|
|
|
char b[BDEVNAME_SIZE];
|
|
|
|
printk(KERN_ERR "Buffer I/O error on device %s, logical block %llu\n",
|
|
|
|
bdevname(bh->b_bdev, b),
|
|
|
|
(unsigned long long)bh->b_blocknr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ext4_end_bio(struct bio *bio, int error)
|
|
|
|
{
|
|
|
|
ext4_io_end_t *io_end = bio->bi_private;
|
|
|
|
struct inode *inode;
|
|
|
|
int i;
|
2013-04-12 11:48:32 +08:00
|
|
|
int blocksize;
|
ext4: Fix data corruption with multi-block writepages support
This fixes a corruption problem with the multi-block
writepages submittal change for ext4, from commit
bd2d0210cf22f2bd0cef72eb97cf94fc7d31d8cc ("ext4: use bio
layer instead of buffer layer in mpage_da_submit_io").
(Note that this corruption is not present in 2.6.37 on
ext4, because the corruption was detected after the
feature was merged in 2.6.37-rc1, and so it was turned
off by adding a non-default mount option,
mblk_io_submit. With this commit, which hopefully
fixes the last of the bugs with this feature, we'll be
able to turn on this performance feature by default in
2.6.38, and remove the mblk_io_submit option.)
The ext4 code path to bundle multiple pages for
writeback in ext4_bio_write_page() had a bug: we should
be clearing buffer head dirty flags *before* we submit
the bio, not in the completion routine.
The patch below was tested on 2.6.37 under KVM with the
postgresql script which was submitted by Jon Nelson as
documented in commit 1449032be1.
Without the patch, I'd hit the corruption problem about
50-70% of the time. With the patch, I executed the
script > 100 times with no corruption seen.
I also fixed a bug to make sure ext4_end_bio() doesn't
dereference the bio after the bio_put() call.
Reported-by: Jon Nelson <jnelson@jamponi.net>
Reported-by: Matthias Bayer <jackdachef@gmail.com>
Signed-off-by: Curt Wohlgemuth <curtw@google.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Cc: stable@kernel.org
2011-02-08 01:46:14 +08:00
|
|
|
sector_t bi_sector = bio->bi_sector;
|
2010-10-28 09:30:10 +08:00
|
|
|
|
|
|
|
BUG_ON(!io_end);
|
2013-04-12 11:48:32 +08:00
|
|
|
inode = io_end->inode;
|
|
|
|
blocksize = 1 << inode->i_blkbits;
|
2010-10-28 09:30:10 +08:00
|
|
|
bio->bi_private = NULL;
|
|
|
|
bio->bi_end_io = NULL;
|
|
|
|
if (test_bit(BIO_UPTODATE, &bio->bi_flags))
|
|
|
|
error = 0;
|
2013-04-12 11:48:32 +08:00
|
|
|
for (i = 0; i < bio->bi_vcnt; i++) {
|
|
|
|
struct bio_vec *bvec = &bio->bi_io_vec[i];
|
|
|
|
struct page *page = bvec->bv_page;
|
2010-10-28 09:30:10 +08:00
|
|
|
struct buffer_head *bh, *head;
|
2013-04-12 11:48:32 +08:00
|
|
|
unsigned bio_start = bvec->bv_offset;
|
|
|
|
unsigned bio_end = bio_start + bvec->bv_len;
|
|
|
|
unsigned under_io = 0;
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
if (!page)
|
|
|
|
continue;
|
2010-10-28 09:30:10 +08:00
|
|
|
|
2011-05-01 01:26:26 +08:00
|
|
|
if (error) {
|
2010-10-28 09:30:10 +08:00
|
|
|
SetPageError(page);
|
2011-05-01 01:26:26 +08:00
|
|
|
set_bit(AS_EIO, &page->mapping->flags);
|
2010-10-28 09:30:10 +08:00
|
|
|
}
|
2013-04-12 11:48:32 +08:00
|
|
|
bh = head = page_buffers(page);
|
|
|
|
/*
|
|
|
|
* We check all buffers in the page under BH_Uptodate_Lock
|
|
|
|
* to avoid races with other end io clearing async_write flags
|
|
|
|
*/
|
|
|
|
local_irq_save(flags);
|
|
|
|
bit_spin_lock(BH_Uptodate_Lock, &head->b_state);
|
|
|
|
do {
|
|
|
|
if (bh_offset(bh) < bio_start ||
|
|
|
|
bh_offset(bh) + blocksize > bio_end) {
|
|
|
|
if (buffer_async_write(bh))
|
|
|
|
under_io++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
clear_buffer_async_write(bh);
|
|
|
|
if (error)
|
|
|
|
buffer_io_error(bh);
|
|
|
|
} while ((bh = bh->b_this_page) != head);
|
|
|
|
bit_spin_unlock(BH_Uptodate_Lock, &head->b_state);
|
|
|
|
local_irq_restore(flags);
|
|
|
|
if (!under_io)
|
|
|
|
end_page_writeback(page);
|
2010-10-28 09:30:10 +08:00
|
|
|
}
|
2013-04-12 11:48:32 +08:00
|
|
|
bio_put(bio);
|
2010-11-09 02:43:33 +08:00
|
|
|
|
|
|
|
if (error) {
|
|
|
|
io_end->flag |= EXT4_IO_END_ERROR;
|
|
|
|
ext4_warning(inode->i_sb, "I/O error writing to inode %lu "
|
|
|
|
"(offset %llu size %ld starting block %llu)",
|
|
|
|
inode->i_ino,
|
|
|
|
(unsigned long long) io_end->offset,
|
|
|
|
(long) io_end->size,
|
|
|
|
(unsigned long long)
|
ext4: Fix data corruption with multi-block writepages support
This fixes a corruption problem with the multi-block
writepages submittal change for ext4, from commit
bd2d0210cf22f2bd0cef72eb97cf94fc7d31d8cc ("ext4: use bio
layer instead of buffer layer in mpage_da_submit_io").
(Note that this corruption is not present in 2.6.37 on
ext4, because the corruption was detected after the
feature was merged in 2.6.37-rc1, and so it was turned
off by adding a non-default mount option,
mblk_io_submit. With this commit, which hopefully
fixes the last of the bugs with this feature, we'll be
able to turn on this performance feature by default in
2.6.38, and remove the mblk_io_submit option.)
The ext4 code path to bundle multiple pages for
writeback in ext4_bio_write_page() had a bug: we should
be clearing buffer head dirty flags *before* we submit
the bio, not in the completion routine.
The patch below was tested on 2.6.37 under KVM with the
postgresql script which was submitted by Jon Nelson as
documented in commit 1449032be1.
Without the patch, I'd hit the corruption problem about
50-70% of the time. With the patch, I executed the
script > 100 times with no corruption seen.
I also fixed a bug to make sure ext4_end_bio() doesn't
dereference the bio after the bio_put() call.
Reported-by: Jon Nelson <jnelson@jamponi.net>
Reported-by: Matthias Bayer <jackdachef@gmail.com>
Signed-off-by: Curt Wohlgemuth <curtw@google.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Cc: stable@kernel.org
2011-02-08 01:46:14 +08:00
|
|
|
bi_sector >> (inode->i_blkbits - 9));
|
2010-11-09 02:43:33 +08:00
|
|
|
}
|
2010-10-28 09:30:10 +08:00
|
|
|
|
2013-05-12 07:07:42 +08:00
|
|
|
if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
|
|
|
|
ext4_free_io_end(io_end);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ext4_add_complete_io(io_end);
|
2010-10-28 09:30:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ext4_io_submit(struct ext4_io_submit *io)
|
|
|
|
{
|
|
|
|
struct bio *bio = io->io_bio;
|
|
|
|
|
|
|
|
if (bio) {
|
|
|
|
bio_get(io->io_bio);
|
|
|
|
submit_bio(io->io_op, io->io_bio);
|
|
|
|
BUG_ON(bio_flagged(io->io_bio, BIO_EOPNOTSUPP));
|
|
|
|
bio_put(io->io_bio);
|
|
|
|
}
|
2011-02-22 10:01:42 +08:00
|
|
|
io->io_bio = NULL;
|
2013-05-12 07:07:42 +08:00
|
|
|
io->io_op = 0;
|
2011-02-22 10:01:42 +08:00
|
|
|
io->io_end = NULL;
|
2010-10-28 09:30:10 +08:00
|
|
|
}
|
|
|
|
|
2013-05-12 07:07:42 +08:00
|
|
|
static int io_submit_init(struct ext4_io_submit *io,
|
|
|
|
struct inode *inode,
|
|
|
|
struct writeback_control *wbc,
|
|
|
|
struct buffer_head *bh)
|
2010-10-28 09:30:10 +08:00
|
|
|
{
|
2013-05-12 07:07:42 +08:00
|
|
|
ext4_io_end_t *io_end;
|
|
|
|
struct page *page = bh->b_page;
|
2010-10-28 09:30:10 +08:00
|
|
|
int nvecs = bio_get_nr_vecs(bh->b_bdev);
|
|
|
|
struct bio *bio;
|
|
|
|
|
2013-05-12 07:07:42 +08:00
|
|
|
io_end = ext4_init_io_end(inode, GFP_NOFS);
|
|
|
|
if (!io_end)
|
|
|
|
return -ENOMEM;
|
2011-06-30 09:44:45 +08:00
|
|
|
bio = bio_alloc(GFP_NOIO, min(nvecs, BIO_MAX_PAGES));
|
2010-10-28 09:30:10 +08:00
|
|
|
bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);
|
|
|
|
bio->bi_bdev = bh->b_bdev;
|
2013-05-12 07:07:42 +08:00
|
|
|
bio->bi_private = io->io_end = io_end;
|
2010-10-28 09:30:10 +08:00
|
|
|
bio->bi_end_io = ext4_end_bio;
|
2013-05-12 07:07:42 +08:00
|
|
|
|
|
|
|
io_end->offset = (page->index << PAGE_CACHE_SHIFT) + bh_offset(bh);
|
|
|
|
|
2010-10-28 09:30:10 +08:00
|
|
|
io->io_bio = bio;
|
2013-05-12 07:07:42 +08:00
|
|
|
io->io_op = (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE);
|
2010-10-28 09:30:10 +08:00
|
|
|
io->io_next_block = bh->b_blocknr;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int io_submit_add_bh(struct ext4_io_submit *io,
|
|
|
|
struct inode *inode,
|
2013-05-12 07:07:42 +08:00
|
|
|
struct writeback_control *wbc,
|
2010-10-28 09:30:10 +08:00
|
|
|
struct buffer_head *bh)
|
|
|
|
{
|
|
|
|
ext4_io_end_t *io_end;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (io->io_bio && bh->b_blocknr != io->io_next_block) {
|
|
|
|
submit_and_retry:
|
|
|
|
ext4_io_submit(io);
|
|
|
|
}
|
|
|
|
if (io->io_bio == NULL) {
|
2013-05-12 07:07:42 +08:00
|
|
|
ret = io_submit_init(io, inode, wbc, bh);
|
2010-10-28 09:30:10 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
io_end = io->io_end;
|
2013-04-12 12:03:19 +08:00
|
|
|
if (test_clear_buffer_uninit(bh))
|
2011-11-01 05:30:44 +08:00
|
|
|
ext4_set_io_unwritten_flag(inode, io_end);
|
2013-05-12 07:07:42 +08:00
|
|
|
io->io_end->size += bh->b_size;
|
2010-10-28 09:30:10 +08:00
|
|
|
io->io_next_block++;
|
2013-05-12 07:07:42 +08:00
|
|
|
ret = bio_add_page(io->io_bio, bh->b_page, bh->b_size, bh_offset(bh));
|
|
|
|
if (ret != bh->b_size)
|
|
|
|
goto submit_and_retry;
|
2010-10-28 09:30:10 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ext4_bio_write_page(struct ext4_io_submit *io,
|
|
|
|
struct page *page,
|
|
|
|
int len,
|
|
|
|
struct writeback_control *wbc)
|
|
|
|
{
|
|
|
|
struct inode *inode = page->mapping->host;
|
2013-04-12 11:48:32 +08:00
|
|
|
unsigned block_start, blocksize;
|
2010-10-28 09:30:10 +08:00
|
|
|
struct buffer_head *bh, *head;
|
|
|
|
int ret = 0;
|
2013-04-12 11:48:32 +08:00
|
|
|
int nr_submitted = 0;
|
2010-10-28 09:30:10 +08:00
|
|
|
|
|
|
|
blocksize = 1 << inode->i_blkbits;
|
|
|
|
|
ext4: Fix data corruption with multi-block writepages support
This fixes a corruption problem with the multi-block
writepages submittal change for ext4, from commit
bd2d0210cf22f2bd0cef72eb97cf94fc7d31d8cc ("ext4: use bio
layer instead of buffer layer in mpage_da_submit_io").
(Note that this corruption is not present in 2.6.37 on
ext4, because the corruption was detected after the
feature was merged in 2.6.37-rc1, and so it was turned
off by adding a non-default mount option,
mblk_io_submit. With this commit, which hopefully
fixes the last of the bugs with this feature, we'll be
able to turn on this performance feature by default in
2.6.38, and remove the mblk_io_submit option.)
The ext4 code path to bundle multiple pages for
writeback in ext4_bio_write_page() had a bug: we should
be clearing buffer head dirty flags *before* we submit
the bio, not in the completion routine.
The patch below was tested on 2.6.37 under KVM with the
postgresql script which was submitted by Jon Nelson as
documented in commit 1449032be1.
Without the patch, I'd hit the corruption problem about
50-70% of the time. With the patch, I executed the
script > 100 times with no corruption seen.
I also fixed a bug to make sure ext4_end_bio() doesn't
dereference the bio after the bio_put() call.
Reported-by: Jon Nelson <jnelson@jamponi.net>
Reported-by: Matthias Bayer <jackdachef@gmail.com>
Signed-off-by: Curt Wohlgemuth <curtw@google.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Cc: stable@kernel.org
2011-02-08 01:46:14 +08:00
|
|
|
BUG_ON(!PageLocked(page));
|
2010-10-28 09:30:10 +08:00
|
|
|
BUG_ON(PageWriteback(page));
|
|
|
|
|
2011-02-28 05:43:24 +08:00
|
|
|
set_page_writeback(page);
|
|
|
|
ClearPageError(page);
|
2010-10-28 09:30:10 +08:00
|
|
|
|
2013-04-12 11:48:32 +08:00
|
|
|
/*
|
|
|
|
* In the first loop we prepare and mark buffers to submit. We have to
|
|
|
|
* mark all buffers in the page before submitting so that
|
|
|
|
* end_page_writeback() cannot be called from ext4_bio_end_io() when IO
|
|
|
|
* on the first buffer finishes and we are still working on submitting
|
|
|
|
* the second buffer.
|
|
|
|
*/
|
|
|
|
bh = head = page_buffers(page);
|
|
|
|
do {
|
|
|
|
block_start = bh_offset(bh);
|
2010-10-28 09:30:10 +08:00
|
|
|
if (block_start >= len) {
|
2011-12-14 11:29:12 +08:00
|
|
|
/*
|
|
|
|
* Comments copied from block_write_full_page_endio:
|
|
|
|
*
|
|
|
|
* The page straddles i_size. It must be zeroed out on
|
|
|
|
* each and every writepage invocation because it may
|
|
|
|
* be mmapped. "A file is mapped in multiples of the
|
|
|
|
* page size. For a file that is not a multiple of
|
|
|
|
* the page size, the remaining memory is zeroed when
|
|
|
|
* mapped, and writes to that region are not written
|
|
|
|
* out to the file."
|
|
|
|
*/
|
2013-04-12 11:48:32 +08:00
|
|
|
zero_user_segment(page, block_start,
|
|
|
|
block_start + blocksize);
|
2010-10-28 09:30:10 +08:00
|
|
|
clear_buffer_dirty(bh);
|
|
|
|
set_buffer_uptodate(bh);
|
|
|
|
continue;
|
|
|
|
}
|
2013-01-29 09:53:28 +08:00
|
|
|
if (!buffer_dirty(bh) || buffer_delay(bh) ||
|
|
|
|
!buffer_mapped(bh) || buffer_unwritten(bh)) {
|
|
|
|
/* A hole? We can safely clear the dirty bit */
|
|
|
|
if (!buffer_mapped(bh))
|
|
|
|
clear_buffer_dirty(bh);
|
|
|
|
if (io->io_bio)
|
|
|
|
ext4_io_submit(io);
|
|
|
|
continue;
|
|
|
|
}
|
2013-04-12 11:48:32 +08:00
|
|
|
if (buffer_new(bh)) {
|
|
|
|
clear_buffer_new(bh);
|
|
|
|
unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr);
|
|
|
|
}
|
|
|
|
set_buffer_async_write(bh);
|
|
|
|
} while ((bh = bh->b_this_page) != head);
|
|
|
|
|
|
|
|
/* Now submit buffers to write */
|
|
|
|
bh = head = page_buffers(page);
|
|
|
|
do {
|
|
|
|
if (!buffer_async_write(bh))
|
|
|
|
continue;
|
2013-05-12 07:07:42 +08:00
|
|
|
ret = io_submit_add_bh(io, inode, wbc, bh);
|
2010-10-28 09:30:10 +08:00
|
|
|
if (ret) {
|
|
|
|
/*
|
|
|
|
* We only get here on ENOMEM. Not much else
|
|
|
|
* we can do but mark the page as dirty, and
|
|
|
|
* better luck next time.
|
|
|
|
*/
|
2013-01-28 22:32:54 +08:00
|
|
|
redirty_page_for_writepage(wbc, page);
|
2010-10-28 09:30:10 +08:00
|
|
|
break;
|
|
|
|
}
|
2013-04-12 11:48:32 +08:00
|
|
|
nr_submitted++;
|
2013-01-28 22:32:54 +08:00
|
|
|
clear_buffer_dirty(bh);
|
2013-04-12 11:48:32 +08:00
|
|
|
} while ((bh = bh->b_this_page) != head);
|
|
|
|
|
|
|
|
/* Error stopped previous loop? Clean up buffers... */
|
|
|
|
if (ret) {
|
|
|
|
do {
|
|
|
|
clear_buffer_async_write(bh);
|
|
|
|
bh = bh->b_this_page;
|
|
|
|
} while (bh != head);
|
2010-10-28 09:30:10 +08:00
|
|
|
}
|
|
|
|
unlock_page(page);
|
2013-04-12 11:48:32 +08:00
|
|
|
/* Nothing submitted - we have to end page writeback */
|
|
|
|
if (!nr_submitted)
|
|
|
|
end_page_writeback(page);
|
2010-10-28 09:30:10 +08:00
|
|
|
return ret;
|
|
|
|
}
|