2005-04-16 22:20:36 +00:00
|
|
|
/*
|
2005-11-02 03:58:39 +00:00
|
|
|
* Copyright (c) 2000-2005 Silicon Graphics, Inc.
|
|
|
|
* All Rights Reserved.
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
2005-11-02 03:58:39 +00:00
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
2005-04-16 22:20:36 +00:00
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
2005-11-02 03:58:39 +00:00
|
|
|
* This program is distributed in the hope that it would be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
2005-11-02 03:58:39 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
|
|
|
#include "xfs.h"
|
2005-11-02 03:38:42 +00:00
|
|
|
#include "xfs_bit.h"
|
2005-04-16 22:20:36 +00:00
|
|
|
#include "xfs_log.h"
|
2005-11-02 03:38:42 +00:00
|
|
|
#include "xfs_inum.h"
|
2005-04-16 22:20:36 +00:00
|
|
|
#include "xfs_sb.h"
|
2005-11-02 03:38:42 +00:00
|
|
|
#include "xfs_ag.h"
|
2005-04-16 22:20:36 +00:00
|
|
|
#include "xfs_dir2.h"
|
|
|
|
#include "xfs_trans.h"
|
|
|
|
#include "xfs_dmapi.h"
|
|
|
|
#include "xfs_mount.h"
|
|
|
|
#include "xfs_bmap_btree.h"
|
|
|
|
#include "xfs_alloc_btree.h"
|
|
|
|
#include "xfs_ialloc_btree.h"
|
|
|
|
#include "xfs_dir2_sf.h"
|
2005-11-02 03:38:42 +00:00
|
|
|
#include "xfs_attr_sf.h"
|
2005-04-16 22:20:36 +00:00
|
|
|
#include "xfs_dinode.h"
|
|
|
|
#include "xfs_inode.h"
|
2005-11-02 03:38:42 +00:00
|
|
|
#include "xfs_alloc.h"
|
|
|
|
#include "xfs_btree.h"
|
2005-04-16 22:20:36 +00:00
|
|
|
#include "xfs_error.h"
|
|
|
|
#include "xfs_rw.h"
|
|
|
|
#include "xfs_iomap.h"
|
2007-08-29 00:58:01 +00:00
|
|
|
#include "xfs_vnodeops.h"
|
2009-12-14 23:14:59 +00:00
|
|
|
#include "xfs_trace.h"
|
2010-03-05 02:00:42 +00:00
|
|
|
#include "xfs_bmap.h"
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 08:04:11 +00:00
|
|
|
#include <linux/gfp.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <linux/mpage.h>
|
2006-01-11 09:48:14 +00:00
|
|
|
#include <linux/pagevec.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <linux/writeback.h>
|
|
|
|
|
2010-04-28 12:28:57 +00:00
|
|
|
/*
|
|
|
|
* Types of I/O for bmap clustering and I/O completion tracking.
|
|
|
|
*/
|
|
|
|
enum {
|
|
|
|
IO_READ, /* mapping for a read */
|
|
|
|
IO_DELAY, /* mapping covers delalloc region */
|
|
|
|
IO_UNWRITTEN, /* mapping covers allocated but uninitialized data */
|
|
|
|
IO_NEW /* just allocated */
|
|
|
|
};
|
2008-12-03 11:20:39 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Prime number of hash buckets since address is used as the key.
|
|
|
|
*/
|
|
|
|
#define NVSYNC 37
|
|
|
|
#define to_ioend_wq(v) (&xfs_ioend_wq[((unsigned long)v) % NVSYNC])
|
|
|
|
static wait_queue_head_t xfs_ioend_wq[NVSYNC];
|
|
|
|
|
|
|
|
void __init
|
|
|
|
xfs_ioend_init(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NVSYNC; i++)
|
|
|
|
init_waitqueue_head(&xfs_ioend_wq[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
xfs_ioend_wait(
|
|
|
|
xfs_inode_t *ip)
|
|
|
|
{
|
|
|
|
wait_queue_head_t *wq = to_ioend_wq(ip);
|
|
|
|
|
|
|
|
wait_event(*wq, (atomic_read(&ip->i_iocount) == 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC void
|
|
|
|
xfs_ioend_wake(
|
|
|
|
xfs_inode_t *ip)
|
|
|
|
{
|
|
|
|
if (atomic_dec_and_test(&ip->i_iocount))
|
|
|
|
wake_up(to_ioend_wq(ip));
|
|
|
|
}
|
|
|
|
|
2009-12-14 23:14:59 +00:00
|
|
|
void
|
2006-03-14 02:26:27 +00:00
|
|
|
xfs_count_page_state(
|
|
|
|
struct page *page,
|
|
|
|
int *delalloc,
|
|
|
|
int *unmapped,
|
|
|
|
int *unwritten)
|
|
|
|
{
|
|
|
|
struct buffer_head *bh, *head;
|
|
|
|
|
|
|
|
*delalloc = *unmapped = *unwritten = 0;
|
|
|
|
|
|
|
|
bh = head = page_buffers(page);
|
|
|
|
do {
|
|
|
|
if (buffer_uptodate(bh) && !buffer_mapped(bh))
|
|
|
|
(*unmapped) = 1;
|
|
|
|
else if (buffer_unwritten(bh))
|
|
|
|
(*unwritten) = 1;
|
|
|
|
else if (buffer_delay(bh))
|
|
|
|
(*delalloc) = 1;
|
|
|
|
} while ((bh = bh->b_this_page) != head);
|
|
|
|
}
|
|
|
|
|
2007-09-14 05:23:17 +00:00
|
|
|
STATIC struct block_device *
|
|
|
|
xfs_find_bdev_for_inode(
|
2010-04-28 12:28:52 +00:00
|
|
|
struct inode *inode)
|
2007-09-14 05:23:17 +00:00
|
|
|
{
|
2010-04-28 12:28:52 +00:00
|
|
|
struct xfs_inode *ip = XFS_I(inode);
|
2007-09-14 05:23:17 +00:00
|
|
|
struct xfs_mount *mp = ip->i_mount;
|
|
|
|
|
2007-11-23 05:29:42 +00:00
|
|
|
if (XFS_IS_REALTIME_INODE(ip))
|
2007-09-14 05:23:17 +00:00
|
|
|
return mp->m_rtdev_targp->bt_bdev;
|
|
|
|
else
|
|
|
|
return mp->m_ddev_targp->bt_bdev;
|
|
|
|
}
|
|
|
|
|
2006-01-11 04:40:13 +00:00
|
|
|
/*
|
|
|
|
* We're now finished for good with this ioend structure.
|
|
|
|
* Update the page state via the associated buffer_heads,
|
|
|
|
* release holds on the inode and bio, and finally free
|
|
|
|
* up memory. Do not use the ioend after this.
|
|
|
|
*/
|
2005-09-02 06:58:49 +00:00
|
|
|
STATIC void
|
|
|
|
xfs_destroy_ioend(
|
|
|
|
xfs_ioend_t *ioend)
|
|
|
|
{
|
2006-01-11 04:40:13 +00:00
|
|
|
struct buffer_head *bh, *next;
|
2008-12-03 11:20:38 +00:00
|
|
|
struct xfs_inode *ip = XFS_I(ioend->io_inode);
|
2006-01-11 04:40:13 +00:00
|
|
|
|
|
|
|
for (bh = ioend->io_buffer_head; bh; bh = next) {
|
|
|
|
next = bh->b_private;
|
2006-06-09 04:58:38 +00:00
|
|
|
bh->b_end_io(bh, !ioend->io_error);
|
2006-01-11 04:40:13 +00:00
|
|
|
}
|
2008-12-03 11:20:38 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Volume managers supporting multiple paths can send back ENODEV
|
|
|
|
* when the final path disappears. In this case continuing to fill
|
|
|
|
* the page cache with dirty data which cannot be written out is
|
|
|
|
* evil, so prevent that.
|
|
|
|
*/
|
|
|
|
if (unlikely(ioend->io_error == -ENODEV)) {
|
|
|
|
xfs_do_force_shutdown(ip->i_mount, SHUTDOWN_DEVICE_REQ,
|
|
|
|
__FILE__, __LINE__);
|
2007-08-29 01:46:28 +00:00
|
|
|
}
|
2008-12-03 11:20:38 +00:00
|
|
|
|
2008-12-03 11:20:39 +00:00
|
|
|
xfs_ioend_wake(ip);
|
2005-09-02 06:58:49 +00:00
|
|
|
mempool_free(ioend, xfs_ioend_pool);
|
|
|
|
}
|
|
|
|
|
2009-10-06 20:29:29 +00:00
|
|
|
/*
|
|
|
|
* If the end of the current ioend is beyond the current EOF,
|
|
|
|
* return the new EOF value, otherwise zero.
|
|
|
|
*/
|
|
|
|
STATIC xfs_fsize_t
|
|
|
|
xfs_ioend_new_eof(
|
|
|
|
xfs_ioend_t *ioend)
|
|
|
|
{
|
|
|
|
xfs_inode_t *ip = XFS_I(ioend->io_inode);
|
|
|
|
xfs_fsize_t isize;
|
|
|
|
xfs_fsize_t bsize;
|
|
|
|
|
|
|
|
bsize = ioend->io_offset + ioend->io_size;
|
|
|
|
isize = MAX(ip->i_size, ip->i_new_size);
|
|
|
|
isize = MIN(isize, bsize);
|
|
|
|
return isize > ip->i_d.di_size ? isize : 0;
|
|
|
|
}
|
|
|
|
|
[XFS] Fix to prevent the notorious 'NULL files' problem after a crash.
The problem that has been addressed is that of synchronising updates of
the file size with writes that extend a file. Without the fix the update
of a file's size, as a result of a write beyond eof, is independent of
when the cached data is flushed to disk. Often the file size update would
be written to the filesystem log before the data is flushed to disk. When
a system crashes between these two events and the filesystem log is
replayed on mount the file's size will be set but since the contents never
made it to disk the file is full of holes. If some of the cached data was
flushed to disk then it may just be a section of the file at the end that
has holes.
There are existing fixes to help alleviate this problem, particularly in
the case where a file has been truncated, that force cached data to be
flushed to disk when the file is closed. If the system crashes while the
file(s) are still open then this flushing will never occur.
The fix that we have implemented is to introduce a second file size,
called the in-memory file size, that represents the current file size as
viewed by the user. The existing file size, called the on-disk file size,
is the one that get's written to the filesystem log and we only update it
when it is safe to do so. When we write to a file beyond eof we only
update the in- memory file size in the write operation. Later when the I/O
operation, that flushes the cached data to disk completes, an I/O
completion routine will update the on-disk file size. The on-disk file
size will be updated to the maximum offset of the I/O or to the value of
the in-memory file size if the I/O includes eof.
SGI-PV: 958522
SGI-Modid: xfs-linux-melb:xfs-kern:28322a
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
2007-05-08 03:49:46 +00:00
|
|
|
/*
|
2010-02-17 05:36:29 +00:00
|
|
|
* Update on-disk file size now that data has been written to disk. The
|
|
|
|
* current in-memory file size is i_size. If a write is beyond eof i_new_size
|
|
|
|
* will be the intended file size until i_size is updated. If this write does
|
|
|
|
* not extend all the way to the valid file size then restrict this update to
|
|
|
|
* the end of the write.
|
|
|
|
*
|
|
|
|
* This function does not block as blocking on the inode lock in IO completion
|
|
|
|
* can lead to IO completion order dependency deadlocks.. If it can't get the
|
|
|
|
* inode ilock it will return EAGAIN. Callers must handle this.
|
[XFS] Fix to prevent the notorious 'NULL files' problem after a crash.
The problem that has been addressed is that of synchronising updates of
the file size with writes that extend a file. Without the fix the update
of a file's size, as a result of a write beyond eof, is independent of
when the cached data is flushed to disk. Often the file size update would
be written to the filesystem log before the data is flushed to disk. When
a system crashes between these two events and the filesystem log is
replayed on mount the file's size will be set but since the contents never
made it to disk the file is full of holes. If some of the cached data was
flushed to disk then it may just be a section of the file at the end that
has holes.
There are existing fixes to help alleviate this problem, particularly in
the case where a file has been truncated, that force cached data to be
flushed to disk when the file is closed. If the system crashes while the
file(s) are still open then this flushing will never occur.
The fix that we have implemented is to introduce a second file size,
called the in-memory file size, that represents the current file size as
viewed by the user. The existing file size, called the on-disk file size,
is the one that get's written to the filesystem log and we only update it
when it is safe to do so. When we write to a file beyond eof we only
update the in- memory file size in the write operation. Later when the I/O
operation, that flushes the cached data to disk completes, an I/O
completion routine will update the on-disk file size. The on-disk file
size will be updated to the maximum offset of the I/O or to the value of
the in-memory file size if the I/O includes eof.
SGI-PV: 958522
SGI-Modid: xfs-linux-melb:xfs-kern:28322a
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
2007-05-08 03:49:46 +00:00
|
|
|
*/
|
2010-02-17 05:36:29 +00:00
|
|
|
STATIC int
|
[XFS] Fix to prevent the notorious 'NULL files' problem after a crash.
The problem that has been addressed is that of synchronising updates of
the file size with writes that extend a file. Without the fix the update
of a file's size, as a result of a write beyond eof, is independent of
when the cached data is flushed to disk. Often the file size update would
be written to the filesystem log before the data is flushed to disk. When
a system crashes between these two events and the filesystem log is
replayed on mount the file's size will be set but since the contents never
made it to disk the file is full of holes. If some of the cached data was
flushed to disk then it may just be a section of the file at the end that
has holes.
There are existing fixes to help alleviate this problem, particularly in
the case where a file has been truncated, that force cached data to be
flushed to disk when the file is closed. If the system crashes while the
file(s) are still open then this flushing will never occur.
The fix that we have implemented is to introduce a second file size,
called the in-memory file size, that represents the current file size as
viewed by the user. The existing file size, called the on-disk file size,
is the one that get's written to the filesystem log and we only update it
when it is safe to do so. When we write to a file beyond eof we only
update the in- memory file size in the write operation. Later when the I/O
operation, that flushes the cached data to disk completes, an I/O
completion routine will update the on-disk file size. The on-disk file
size will be updated to the maximum offset of the I/O or to the value of
the in-memory file size if the I/O includes eof.
SGI-PV: 958522
SGI-Modid: xfs-linux-melb:xfs-kern:28322a
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
2007-05-08 03:49:46 +00:00
|
|
|
xfs_setfilesize(
|
|
|
|
xfs_ioend_t *ioend)
|
|
|
|
{
|
2007-08-29 01:46:28 +00:00
|
|
|
xfs_inode_t *ip = XFS_I(ioend->io_inode);
|
[XFS] Fix to prevent the notorious 'NULL files' problem after a crash.
The problem that has been addressed is that of synchronising updates of
the file size with writes that extend a file. Without the fix the update
of a file's size, as a result of a write beyond eof, is independent of
when the cached data is flushed to disk. Often the file size update would
be written to the filesystem log before the data is flushed to disk. When
a system crashes between these two events and the filesystem log is
replayed on mount the file's size will be set but since the contents never
made it to disk the file is full of holes. If some of the cached data was
flushed to disk then it may just be a section of the file at the end that
has holes.
There are existing fixes to help alleviate this problem, particularly in
the case where a file has been truncated, that force cached data to be
flushed to disk when the file is closed. If the system crashes while the
file(s) are still open then this flushing will never occur.
The fix that we have implemented is to introduce a second file size,
called the in-memory file size, that represents the current file size as
viewed by the user. The existing file size, called the on-disk file size,
is the one that get's written to the filesystem log and we only update it
when it is safe to do so. When we write to a file beyond eof we only
update the in- memory file size in the write operation. Later when the I/O
operation, that flushes the cached data to disk completes, an I/O
completion routine will update the on-disk file size. The on-disk file
size will be updated to the maximum offset of the I/O or to the value of
the in-memory file size if the I/O includes eof.
SGI-PV: 958522
SGI-Modid: xfs-linux-melb:xfs-kern:28322a
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
2007-05-08 03:49:46 +00:00
|
|
|
xfs_fsize_t isize;
|
|
|
|
|
|
|
|
ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFREG);
|
2010-04-28 12:28:57 +00:00
|
|
|
ASSERT(ioend->io_type != IO_READ);
|
[XFS] Fix to prevent the notorious 'NULL files' problem after a crash.
The problem that has been addressed is that of synchronising updates of
the file size with writes that extend a file. Without the fix the update
of a file's size, as a result of a write beyond eof, is independent of
when the cached data is flushed to disk. Often the file size update would
be written to the filesystem log before the data is flushed to disk. When
a system crashes between these two events and the filesystem log is
replayed on mount the file's size will be set but since the contents never
made it to disk the file is full of holes. If some of the cached data was
flushed to disk then it may just be a section of the file at the end that
has holes.
There are existing fixes to help alleviate this problem, particularly in
the case where a file has been truncated, that force cached data to be
flushed to disk when the file is closed. If the system crashes while the
file(s) are still open then this flushing will never occur.
The fix that we have implemented is to introduce a second file size,
called the in-memory file size, that represents the current file size as
viewed by the user. The existing file size, called the on-disk file size,
is the one that get's written to the filesystem log and we only update it
when it is safe to do so. When we write to a file beyond eof we only
update the in- memory file size in the write operation. Later when the I/O
operation, that flushes the cached data to disk completes, an I/O
completion routine will update the on-disk file size. The on-disk file
size will be updated to the maximum offset of the I/O or to the value of
the in-memory file size if the I/O includes eof.
SGI-PV: 958522
SGI-Modid: xfs-linux-melb:xfs-kern:28322a
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
2007-05-08 03:49:46 +00:00
|
|
|
|
|
|
|
if (unlikely(ioend->io_error))
|
2010-02-17 05:36:29 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL))
|
|
|
|
return EAGAIN;
|
[XFS] Fix to prevent the notorious 'NULL files' problem after a crash.
The problem that has been addressed is that of synchronising updates of
the file size with writes that extend a file. Without the fix the update
of a file's size, as a result of a write beyond eof, is independent of
when the cached data is flushed to disk. Often the file size update would
be written to the filesystem log before the data is flushed to disk. When
a system crashes between these two events and the filesystem log is
replayed on mount the file's size will be set but since the contents never
made it to disk the file is full of holes. If some of the cached data was
flushed to disk then it may just be a section of the file at the end that
has holes.
There are existing fixes to help alleviate this problem, particularly in
the case where a file has been truncated, that force cached data to be
flushed to disk when the file is closed. If the system crashes while the
file(s) are still open then this flushing will never occur.
The fix that we have implemented is to introduce a second file size,
called the in-memory file size, that represents the current file size as
viewed by the user. The existing file size, called the on-disk file size,
is the one that get's written to the filesystem log and we only update it
when it is safe to do so. When we write to a file beyond eof we only
update the in- memory file size in the write operation. Later when the I/O
operation, that flushes the cached data to disk completes, an I/O
completion routine will update the on-disk file size. The on-disk file
size will be updated to the maximum offset of the I/O or to the value of
the in-memory file size if the I/O includes eof.
SGI-PV: 958522
SGI-Modid: xfs-linux-melb:xfs-kern:28322a
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
2007-05-08 03:49:46 +00:00
|
|
|
|
2009-10-06 20:29:29 +00:00
|
|
|
isize = xfs_ioend_new_eof(ioend);
|
|
|
|
if (isize) {
|
[XFS] Fix to prevent the notorious 'NULL files' problem after a crash.
The problem that has been addressed is that of synchronising updates of
the file size with writes that extend a file. Without the fix the update
of a file's size, as a result of a write beyond eof, is independent of
when the cached data is flushed to disk. Often the file size update would
be written to the filesystem log before the data is flushed to disk. When
a system crashes between these two events and the filesystem log is
replayed on mount the file's size will be set but since the contents never
made it to disk the file is full of holes. If some of the cached data was
flushed to disk then it may just be a section of the file at the end that
has holes.
There are existing fixes to help alleviate this problem, particularly in
the case where a file has been truncated, that force cached data to be
flushed to disk when the file is closed. If the system crashes while the
file(s) are still open then this flushing will never occur.
The fix that we have implemented is to introduce a second file size,
called the in-memory file size, that represents the current file size as
viewed by the user. The existing file size, called the on-disk file size,
is the one that get's written to the filesystem log and we only update it
when it is safe to do so. When we write to a file beyond eof we only
update the in- memory file size in the write operation. Later when the I/O
operation, that flushes the cached data to disk completes, an I/O
completion routine will update the on-disk file size. The on-disk file
size will be updated to the maximum offset of the I/O or to the value of
the in-memory file size if the I/O includes eof.
SGI-PV: 958522
SGI-Modid: xfs-linux-melb:xfs-kern:28322a
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
2007-05-08 03:49:46 +00:00
|
|
|
ip->i_d.di_size = isize;
|
2010-02-15 09:44:49 +00:00
|
|
|
xfs_mark_inode_dirty(ip);
|
[XFS] Fix to prevent the notorious 'NULL files' problem after a crash.
The problem that has been addressed is that of synchronising updates of
the file size with writes that extend a file. Without the fix the update
of a file's size, as a result of a write beyond eof, is independent of
when the cached data is flushed to disk. Often the file size update would
be written to the filesystem log before the data is flushed to disk. When
a system crashes between these two events and the filesystem log is
replayed on mount the file's size will be set but since the contents never
made it to disk the file is full of holes. If some of the cached data was
flushed to disk then it may just be a section of the file at the end that
has holes.
There are existing fixes to help alleviate this problem, particularly in
the case where a file has been truncated, that force cached data to be
flushed to disk when the file is closed. If the system crashes while the
file(s) are still open then this flushing will never occur.
The fix that we have implemented is to introduce a second file size,
called the in-memory file size, that represents the current file size as
viewed by the user. The existing file size, called the on-disk file size,
is the one that get's written to the filesystem log and we only update it
when it is safe to do so. When we write to a file beyond eof we only
update the in- memory file size in the write operation. Later when the I/O
operation, that flushes the cached data to disk completes, an I/O
completion routine will update the on-disk file size. The on-disk file
size will be updated to the maximum offset of the I/O or to the value of
the in-memory file size if the I/O includes eof.
SGI-PV: 958522
SGI-Modid: xfs-linux-melb:xfs-kern:28322a
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
2007-05-08 03:49:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
2010-02-17 05:36:29 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Schedule IO completion handling on a xfsdatad if this was
|
|
|
|
* the final hold on this ioend. If we are asked to wait,
|
|
|
|
* flush the workqueue.
|
|
|
|
*/
|
|
|
|
STATIC void
|
|
|
|
xfs_finish_ioend(
|
|
|
|
xfs_ioend_t *ioend,
|
|
|
|
int wait)
|
|
|
|
{
|
|
|
|
if (atomic_dec_and_test(&ioend->io_remaining)) {
|
|
|
|
struct workqueue_struct *wq;
|
|
|
|
|
2010-04-28 12:28:57 +00:00
|
|
|
wq = (ioend->io_type == IO_UNWRITTEN) ?
|
2010-02-17 05:36:29 +00:00
|
|
|
xfsconvertd_workqueue : xfsdatad_workqueue;
|
|
|
|
queue_work(wq, &ioend->io_work);
|
|
|
|
if (wait)
|
|
|
|
flush_workqueue(wq);
|
|
|
|
}
|
[XFS] Fix to prevent the notorious 'NULL files' problem after a crash.
The problem that has been addressed is that of synchronising updates of
the file size with writes that extend a file. Without the fix the update
of a file's size, as a result of a write beyond eof, is independent of
when the cached data is flushed to disk. Often the file size update would
be written to the filesystem log before the data is flushed to disk. When
a system crashes between these two events and the filesystem log is
replayed on mount the file's size will be set but since the contents never
made it to disk the file is full of holes. If some of the cached data was
flushed to disk then it may just be a section of the file at the end that
has holes.
There are existing fixes to help alleviate this problem, particularly in
the case where a file has been truncated, that force cached data to be
flushed to disk when the file is closed. If the system crashes while the
file(s) are still open then this flushing will never occur.
The fix that we have implemented is to introduce a second file size,
called the in-memory file size, that represents the current file size as
viewed by the user. The existing file size, called the on-disk file size,
is the one that get's written to the filesystem log and we only update it
when it is safe to do so. When we write to a file beyond eof we only
update the in- memory file size in the write operation. Later when the I/O
operation, that flushes the cached data to disk completes, an I/O
completion routine will update the on-disk file size. The on-disk file
size will be updated to the maximum offset of the I/O or to the value of
the in-memory file size if the I/O includes eof.
SGI-PV: 958522
SGI-Modid: xfs-linux-melb:xfs-kern:28322a
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
2007-05-08 03:49:46 +00:00
|
|
|
}
|
|
|
|
|
2005-09-02 06:58:49 +00:00
|
|
|
/*
|
2009-10-30 09:11:47 +00:00
|
|
|
* IO write completion.
|
2006-01-11 04:40:13 +00:00
|
|
|
*/
|
|
|
|
STATIC void
|
2009-10-30 09:11:47 +00:00
|
|
|
xfs_end_io(
|
2010-02-17 05:36:29 +00:00
|
|
|
struct work_struct *work)
|
2005-09-02 06:58:49 +00:00
|
|
|
{
|
2010-02-17 05:36:29 +00:00
|
|
|
xfs_ioend_t *ioend = container_of(work, xfs_ioend_t, io_work);
|
|
|
|
struct xfs_inode *ip = XFS_I(ioend->io_inode);
|
2010-03-04 00:57:09 +00:00
|
|
|
int error = 0;
|
[XFS] Fix to prevent the notorious 'NULL files' problem after a crash.
The problem that has been addressed is that of synchronising updates of
the file size with writes that extend a file. Without the fix the update
of a file's size, as a result of a write beyond eof, is independent of
when the cached data is flushed to disk. Often the file size update would
be written to the filesystem log before the data is flushed to disk. When
a system crashes between these two events and the filesystem log is
replayed on mount the file's size will be set but since the contents never
made it to disk the file is full of holes. If some of the cached data was
flushed to disk then it may just be a section of the file at the end that
has holes.
There are existing fixes to help alleviate this problem, particularly in
the case where a file has been truncated, that force cached data to be
flushed to disk when the file is closed. If the system crashes while the
file(s) are still open then this flushing will never occur.
The fix that we have implemented is to introduce a second file size,
called the in-memory file size, that represents the current file size as
viewed by the user. The existing file size, called the on-disk file size,
is the one that get's written to the filesystem log and we only update it
when it is safe to do so. When we write to a file beyond eof we only
update the in- memory file size in the write operation. Later when the I/O
operation, that flushes the cached data to disk completes, an I/O
completion routine will update the on-disk file size. The on-disk file
size will be updated to the maximum offset of the I/O or to the value of
the in-memory file size if the I/O includes eof.
SGI-PV: 958522
SGI-Modid: xfs-linux-melb:xfs-kern:28322a
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
2007-05-08 03:49:46 +00:00
|
|
|
|
2009-10-30 09:11:47 +00:00
|
|
|
/*
|
|
|
|
* For unwritten extents we need to issue transactions to convert a
|
|
|
|
* range to normal written extens after the data I/O has finished.
|
|
|
|
*/
|
2010-04-28 12:28:57 +00:00
|
|
|
if (ioend->io_type == IO_UNWRITTEN &&
|
2009-10-30 09:11:47 +00:00
|
|
|
likely(!ioend->io_error && !XFS_FORCED_SHUTDOWN(ip->i_mount))) {
|
|
|
|
|
|
|
|
error = xfs_iomap_write_unwritten(ip, ioend->io_offset,
|
|
|
|
ioend->io_size);
|
|
|
|
if (error)
|
|
|
|
ioend->io_error = error;
|
|
|
|
}
|
[XFS] Fix to prevent the notorious 'NULL files' problem after a crash.
The problem that has been addressed is that of synchronising updates of
the file size with writes that extend a file. Without the fix the update
of a file's size, as a result of a write beyond eof, is independent of
when the cached data is flushed to disk. Often the file size update would
be written to the filesystem log before the data is flushed to disk. When
a system crashes between these two events and the filesystem log is
replayed on mount the file's size will be set but since the contents never
made it to disk the file is full of holes. If some of the cached data was
flushed to disk then it may just be a section of the file at the end that
has holes.
There are existing fixes to help alleviate this problem, particularly in
the case where a file has been truncated, that force cached data to be
flushed to disk when the file is closed. If the system crashes while the
file(s) are still open then this flushing will never occur.
The fix that we have implemented is to introduce a second file size,
called the in-memory file size, that represents the current file size as
viewed by the user. The existing file size, called the on-disk file size,
is the one that get's written to the filesystem log and we only update it
when it is safe to do so. When we write to a file beyond eof we only
update the in- memory file size in the write operation. Later when the I/O
operation, that flushes the cached data to disk completes, an I/O
completion routine will update the on-disk file size. The on-disk file
size will be updated to the maximum offset of the I/O or to the value of
the in-memory file size if the I/O includes eof.
SGI-PV: 958522
SGI-Modid: xfs-linux-melb:xfs-kern:28322a
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
2007-05-08 03:49:46 +00:00
|
|
|
|
2009-10-30 09:11:47 +00:00
|
|
|
/*
|
|
|
|
* We might have to update the on-disk file size after extending
|
|
|
|
* writes.
|
|
|
|
*/
|
2010-04-28 12:28:57 +00:00
|
|
|
if (ioend->io_type != IO_READ) {
|
2010-02-17 05:36:29 +00:00
|
|
|
error = xfs_setfilesize(ioend);
|
|
|
|
ASSERT(!error || error == EAGAIN);
|
2009-04-06 16:42:11 +00:00
|
|
|
}
|
2010-02-17 05:36:29 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we didn't complete processing of the ioend, requeue it to the
|
|
|
|
* tail of the workqueue for another attempt later. Otherwise destroy
|
|
|
|
* it.
|
|
|
|
*/
|
|
|
|
if (error == EAGAIN) {
|
|
|
|
atomic_inc(&ioend->io_remaining);
|
|
|
|
xfs_finish_ioend(ioend, 0);
|
|
|
|
/* ensure we don't spin on blocked ioends */
|
|
|
|
delay(1);
|
|
|
|
} else
|
|
|
|
xfs_destroy_ioend(ioend);
|
2009-04-06 16:42:11 +00:00
|
|
|
}
|
|
|
|
|
2005-09-02 06:58:49 +00:00
|
|
|
/*
|
|
|
|
* Allocate and initialise an IO completion structure.
|
|
|
|
* We need to track unwritten extent write completion here initially.
|
|
|
|
* We'll need to extend this for updating the ondisk inode size later
|
|
|
|
* (vs. incore size).
|
|
|
|
*/
|
|
|
|
STATIC xfs_ioend_t *
|
|
|
|
xfs_alloc_ioend(
|
2006-01-11 04:40:13 +00:00
|
|
|
struct inode *inode,
|
|
|
|
unsigned int type)
|
2005-09-02 06:58:49 +00:00
|
|
|
{
|
|
|
|
xfs_ioend_t *ioend;
|
|
|
|
|
|
|
|
ioend = mempool_alloc(xfs_ioend_pool, GFP_NOFS);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the count to 1 initially, which will prevent an I/O
|
|
|
|
* completion callback from happening before we have started
|
|
|
|
* all the I/O from calling the completion routine too early.
|
|
|
|
*/
|
|
|
|
atomic_set(&ioend->io_remaining, 1);
|
2006-06-09 04:58:38 +00:00
|
|
|
ioend->io_error = 0;
|
2006-01-11 04:40:13 +00:00
|
|
|
ioend->io_list = NULL;
|
|
|
|
ioend->io_type = type;
|
2007-08-29 01:46:28 +00:00
|
|
|
ioend->io_inode = inode;
|
2005-09-04 22:23:35 +00:00
|
|
|
ioend->io_buffer_head = NULL;
|
2006-01-11 04:40:13 +00:00
|
|
|
ioend->io_buffer_tail = NULL;
|
2007-08-29 01:46:28 +00:00
|
|
|
atomic_inc(&XFS_I(ioend->io_inode)->i_iocount);
|
2005-09-02 06:58:49 +00:00
|
|
|
ioend->io_offset = 0;
|
|
|
|
ioend->io_size = 0;
|
|
|
|
|
2009-10-30 09:11:47 +00:00
|
|
|
INIT_WORK(&ioend->io_work, xfs_end_io);
|
2005-09-02 06:58:49 +00:00
|
|
|
return ioend;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
STATIC int
|
|
|
|
xfs_map_blocks(
|
|
|
|
struct inode *inode,
|
|
|
|
loff_t offset,
|
|
|
|
ssize_t count,
|
2010-04-28 12:28:56 +00:00
|
|
|
struct xfs_bmbt_irec *imap,
|
2005-04-16 22:20:36 +00:00
|
|
|
int flags)
|
|
|
|
{
|
2008-12-03 11:20:32 +00:00
|
|
|
int nmaps = 1;
|
2010-04-28 12:28:56 +00:00
|
|
|
int new = 0;
|
2008-12-03 11:20:32 +00:00
|
|
|
|
2010-04-28 12:28:56 +00:00
|
|
|
return -xfs_iomap(XFS_I(inode), offset, count, flags, imap, &nmaps, &new);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2009-11-14 16:17:22 +00:00
|
|
|
STATIC int
|
2010-04-28 12:28:58 +00:00
|
|
|
xfs_imap_valid(
|
2010-04-28 12:28:54 +00:00
|
|
|
struct inode *inode,
|
2010-04-28 12:28:56 +00:00
|
|
|
struct xfs_bmbt_irec *imap,
|
2010-04-28 12:28:58 +00:00
|
|
|
xfs_off_t offset)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2010-04-28 12:28:58 +00:00
|
|
|
offset >>= inode->i_blkbits;
|
2010-04-28 12:28:54 +00:00
|
|
|
|
2010-04-28 12:28:58 +00:00
|
|
|
return offset >= imap->br_startoff &&
|
|
|
|
offset < imap->br_startoff + imap->br_blockcount;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2006-01-11 04:40:13 +00:00
|
|
|
/*
|
|
|
|
* BIO completion handler for buffered IO.
|
|
|
|
*/
|
2007-10-12 06:17:47 +00:00
|
|
|
STATIC void
|
2006-01-11 04:40:13 +00:00
|
|
|
xfs_end_bio(
|
|
|
|
struct bio *bio,
|
|
|
|
int error)
|
|
|
|
{
|
|
|
|
xfs_ioend_t *ioend = bio->bi_private;
|
|
|
|
|
|
|
|
ASSERT(atomic_read(&bio->bi_cnt) >= 1);
|
2006-06-09 04:58:38 +00:00
|
|
|
ioend->io_error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : error;
|
2006-01-11 04:40:13 +00:00
|
|
|
|
|
|
|
/* Toss bio and pass work off to an xfsdatad thread */
|
|
|
|
bio->bi_private = NULL;
|
|
|
|
bio->bi_end_io = NULL;
|
|
|
|
bio_put(bio);
|
2006-06-09 04:58:38 +00:00
|
|
|
|
2007-06-05 06:24:36 +00:00
|
|
|
xfs_finish_ioend(ioend, 0);
|
2006-01-11 04:40:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
STATIC void
|
|
|
|
xfs_submit_ioend_bio(
|
2009-10-30 09:09:15 +00:00
|
|
|
struct writeback_control *wbc,
|
|
|
|
xfs_ioend_t *ioend,
|
|
|
|
struct bio *bio)
|
2006-01-11 04:40:13 +00:00
|
|
|
{
|
|
|
|
atomic_inc(&ioend->io_remaining);
|
|
|
|
bio->bi_private = ioend;
|
|
|
|
bio->bi_end_io = xfs_end_bio;
|
|
|
|
|
2009-10-06 20:29:29 +00:00
|
|
|
/*
|
|
|
|
* If the I/O is beyond EOF we mark the inode dirty immediately
|
|
|
|
* but don't update the inode size until I/O completion.
|
|
|
|
*/
|
|
|
|
if (xfs_ioend_new_eof(ioend))
|
2010-02-15 09:44:49 +00:00
|
|
|
xfs_mark_inode_dirty(XFS_I(ioend->io_inode));
|
2009-10-06 20:29:29 +00:00
|
|
|
|
2009-10-30 09:09:15 +00:00
|
|
|
submit_bio(wbc->sync_mode == WB_SYNC_ALL ?
|
|
|
|
WRITE_SYNC_PLUG : WRITE, bio);
|
2006-01-11 04:40:13 +00:00
|
|
|
ASSERT(!bio_flagged(bio, BIO_EOPNOTSUPP));
|
|
|
|
bio_put(bio);
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC struct bio *
|
|
|
|
xfs_alloc_ioend_bio(
|
|
|
|
struct buffer_head *bh)
|
|
|
|
{
|
|
|
|
struct bio *bio;
|
|
|
|
int nvecs = bio_get_nr_vecs(bh->b_bdev);
|
|
|
|
|
|
|
|
do {
|
|
|
|
bio = bio_alloc(GFP_NOIO, nvecs);
|
|
|
|
nvecs >>= 1;
|
|
|
|
} while (!bio);
|
|
|
|
|
|
|
|
ASSERT(bio->bi_private == NULL);
|
|
|
|
bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);
|
|
|
|
bio->bi_bdev = bh->b_bdev;
|
|
|
|
bio_get(bio);
|
|
|
|
return bio;
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC void
|
|
|
|
xfs_start_buffer_writeback(
|
|
|
|
struct buffer_head *bh)
|
|
|
|
{
|
|
|
|
ASSERT(buffer_mapped(bh));
|
|
|
|
ASSERT(buffer_locked(bh));
|
|
|
|
ASSERT(!buffer_delay(bh));
|
|
|
|
ASSERT(!buffer_unwritten(bh));
|
|
|
|
|
|
|
|
mark_buffer_async_write(bh);
|
|
|
|
set_buffer_uptodate(bh);
|
|
|
|
clear_buffer_dirty(bh);
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC void
|
|
|
|
xfs_start_page_writeback(
|
|
|
|
struct page *page,
|
|
|
|
int clear_dirty,
|
|
|
|
int buffers)
|
|
|
|
{
|
|
|
|
ASSERT(PageLocked(page));
|
|
|
|
ASSERT(!PageWriteback(page));
|
|
|
|
if (clear_dirty)
|
2006-12-20 23:24:01 +00:00
|
|
|
clear_page_dirty_for_io(page);
|
|
|
|
set_page_writeback(page);
|
2006-01-11 04:40:13 +00:00
|
|
|
unlock_page(page);
|
2007-10-17 06:30:42 +00:00
|
|
|
/* If no buffers on the page are to be written, finish it here */
|
|
|
|
if (!buffers)
|
2006-01-11 04:40:13 +00:00
|
|
|
end_page_writeback(page);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int bio_add_buffer(struct bio *bio, struct buffer_head *bh)
|
|
|
|
{
|
|
|
|
return bio_add_page(bio, bh->b_page, bh->b_size, bh_offset(bh));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-01-18 02:38:12 +00:00
|
|
|
* Submit all of the bios for all of the ioends we have saved up, covering the
|
|
|
|
* initial writepage page and also any probed pages.
|
|
|
|
*
|
|
|
|
* Because we may have multiple ioends spanning a page, we need to start
|
|
|
|
* writeback on all the buffers before we submit them for I/O. If we mark the
|
|
|
|
* buffers as we got, then we can end up with a page that only has buffers
|
|
|
|
* marked async write and I/O complete on can occur before we mark the other
|
|
|
|
* buffers async write.
|
|
|
|
*
|
|
|
|
* The end result of this is that we trip a bug in end_page_writeback() because
|
|
|
|
* we call it twice for the one page as the code in end_buffer_async_write()
|
|
|
|
* assumes that all buffers on the page are started at the same time.
|
|
|
|
*
|
|
|
|
* The fix is two passes across the ioend list - one to start writeback on the
|
2006-03-28 22:55:14 +00:00
|
|
|
* buffer_heads, and then submit them for I/O on the second pass.
|
2006-01-11 04:40:13 +00:00
|
|
|
*/
|
|
|
|
STATIC void
|
|
|
|
xfs_submit_ioend(
|
2009-10-30 09:09:15 +00:00
|
|
|
struct writeback_control *wbc,
|
2006-01-11 04:40:13 +00:00
|
|
|
xfs_ioend_t *ioend)
|
|
|
|
{
|
2006-01-18 02:38:12 +00:00
|
|
|
xfs_ioend_t *head = ioend;
|
2006-01-11 04:40:13 +00:00
|
|
|
xfs_ioend_t *next;
|
|
|
|
struct buffer_head *bh;
|
|
|
|
struct bio *bio;
|
|
|
|
sector_t lastblock = 0;
|
|
|
|
|
2006-01-18 02:38:12 +00:00
|
|
|
/* Pass 1 - start writeback */
|
|
|
|
do {
|
|
|
|
next = ioend->io_list;
|
|
|
|
for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) {
|
|
|
|
xfs_start_buffer_writeback(bh);
|
|
|
|
}
|
|
|
|
} while ((ioend = next) != NULL);
|
|
|
|
|
|
|
|
/* Pass 2 - submit I/O */
|
|
|
|
ioend = head;
|
2006-01-11 04:40:13 +00:00
|
|
|
do {
|
|
|
|
next = ioend->io_list;
|
|
|
|
bio = NULL;
|
|
|
|
|
|
|
|
for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) {
|
|
|
|
|
|
|
|
if (!bio) {
|
|
|
|
retry:
|
|
|
|
bio = xfs_alloc_ioend_bio(bh);
|
|
|
|
} else if (bh->b_blocknr != lastblock + 1) {
|
2009-10-30 09:09:15 +00:00
|
|
|
xfs_submit_ioend_bio(wbc, ioend, bio);
|
2006-01-11 04:40:13 +00:00
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bio_add_buffer(bio, bh) != bh->b_size) {
|
2009-10-30 09:09:15 +00:00
|
|
|
xfs_submit_ioend_bio(wbc, ioend, bio);
|
2006-01-11 04:40:13 +00:00
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
|
|
|
lastblock = bh->b_blocknr;
|
|
|
|
}
|
|
|
|
if (bio)
|
2009-10-30 09:09:15 +00:00
|
|
|
xfs_submit_ioend_bio(wbc, ioend, bio);
|
2007-06-05 06:24:36 +00:00
|
|
|
xfs_finish_ioend(ioend, 0);
|
2006-01-11 04:40:13 +00:00
|
|
|
} while ((ioend = next) != NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Cancel submission of all buffer_heads so far in this endio.
|
|
|
|
* Toss the endio too. Only ever called for the initial page
|
|
|
|
* in a writepage request, so only ever one page.
|
|
|
|
*/
|
|
|
|
STATIC void
|
|
|
|
xfs_cancel_ioend(
|
|
|
|
xfs_ioend_t *ioend)
|
|
|
|
{
|
|
|
|
xfs_ioend_t *next;
|
|
|
|
struct buffer_head *bh, *next_bh;
|
|
|
|
|
|
|
|
do {
|
|
|
|
next = ioend->io_list;
|
|
|
|
bh = ioend->io_buffer_head;
|
|
|
|
do {
|
|
|
|
next_bh = bh->b_private;
|
|
|
|
clear_buffer_async_write(bh);
|
|
|
|
unlock_buffer(bh);
|
|
|
|
} while ((bh = next_bh) != NULL);
|
|
|
|
|
2008-12-03 11:20:39 +00:00
|
|
|
xfs_ioend_wake(XFS_I(ioend->io_inode));
|
2006-01-11 04:40:13 +00:00
|
|
|
mempool_free(ioend, xfs_ioend_pool);
|
|
|
|
} while ((ioend = next) != NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Test to see if we've been building up a completion structure for
|
|
|
|
* earlier buffers -- if so, we try to append to this ioend if we
|
|
|
|
* can, otherwise we finish off any current ioend and start another.
|
|
|
|
* Return true if we've finished the given ioend.
|
|
|
|
*/
|
|
|
|
STATIC void
|
|
|
|
xfs_add_to_ioend(
|
|
|
|
struct inode *inode,
|
|
|
|
struct buffer_head *bh,
|
2006-01-11 09:49:16 +00:00
|
|
|
xfs_off_t offset,
|
2006-01-11 04:40:13 +00:00
|
|
|
unsigned int type,
|
|
|
|
xfs_ioend_t **result,
|
|
|
|
int need_ioend)
|
|
|
|
{
|
|
|
|
xfs_ioend_t *ioend = *result;
|
|
|
|
|
|
|
|
if (!ioend || need_ioend || type != ioend->io_type) {
|
|
|
|
xfs_ioend_t *previous = *result;
|
|
|
|
|
|
|
|
ioend = xfs_alloc_ioend(inode, type);
|
|
|
|
ioend->io_offset = offset;
|
|
|
|
ioend->io_buffer_head = bh;
|
|
|
|
ioend->io_buffer_tail = bh;
|
|
|
|
if (previous)
|
|
|
|
previous->io_list = ioend;
|
|
|
|
*result = ioend;
|
|
|
|
} else {
|
|
|
|
ioend->io_buffer_tail->b_private = bh;
|
|
|
|
ioend->io_buffer_tail = bh;
|
|
|
|
}
|
|
|
|
|
|
|
|
bh->b_private = NULL;
|
|
|
|
ioend->io_size += bh->b_size;
|
|
|
|
}
|
|
|
|
|
2006-03-14 02:26:43 +00:00
|
|
|
STATIC void
|
|
|
|
xfs_map_buffer(
|
2010-04-28 12:28:52 +00:00
|
|
|
struct inode *inode,
|
2006-03-14 02:26:43 +00:00
|
|
|
struct buffer_head *bh,
|
2010-04-28 12:28:56 +00:00
|
|
|
struct xfs_bmbt_irec *imap,
|
2010-04-28 12:28:52 +00:00
|
|
|
xfs_off_t offset)
|
2006-03-14 02:26:43 +00:00
|
|
|
{
|
|
|
|
sector_t bn;
|
2010-04-28 12:28:54 +00:00
|
|
|
struct xfs_mount *m = XFS_I(inode)->i_mount;
|
2010-04-28 12:28:56 +00:00
|
|
|
xfs_off_t iomap_offset = XFS_FSB_TO_B(m, imap->br_startoff);
|
|
|
|
xfs_daddr_t iomap_bn = xfs_fsb_to_db(XFS_I(inode), imap->br_startblock);
|
2006-03-14 02:26:43 +00:00
|
|
|
|
2010-04-28 12:28:56 +00:00
|
|
|
ASSERT(imap->br_startblock != HOLESTARTBLOCK);
|
|
|
|
ASSERT(imap->br_startblock != DELAYSTARTBLOCK);
|
2006-03-14 02:26:43 +00:00
|
|
|
|
2010-04-28 12:28:55 +00:00
|
|
|
bn = (iomap_bn >> (inode->i_blkbits - BBSHIFT)) +
|
2010-04-28 12:28:54 +00:00
|
|
|
((offset - iomap_offset) >> inode->i_blkbits);
|
2006-03-14 02:26:43 +00:00
|
|
|
|
2010-04-28 12:28:52 +00:00
|
|
|
ASSERT(bn || XFS_IS_REALTIME_INODE(XFS_I(inode)));
|
2006-03-14 02:26:43 +00:00
|
|
|
|
|
|
|
bh->b_blocknr = bn;
|
|
|
|
set_buffer_mapped(bh);
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
STATIC void
|
|
|
|
xfs_map_at_offset(
|
2010-04-28 12:28:52 +00:00
|
|
|
struct inode *inode,
|
2005-04-16 22:20:36 +00:00
|
|
|
struct buffer_head *bh,
|
2010-04-28 12:28:56 +00:00
|
|
|
struct xfs_bmbt_irec *imap,
|
2010-04-28 12:28:52 +00:00
|
|
|
xfs_off_t offset)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2010-04-28 12:28:56 +00:00
|
|
|
ASSERT(imap->br_startblock != HOLESTARTBLOCK);
|
|
|
|
ASSERT(imap->br_startblock != DELAYSTARTBLOCK);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
lock_buffer(bh);
|
2010-04-28 12:28:56 +00:00
|
|
|
xfs_map_buffer(inode, bh, imap, offset);
|
2010-04-28 12:28:52 +00:00
|
|
|
bh->b_bdev = xfs_find_bdev_for_inode(inode);
|
2005-04-16 22:20:36 +00:00
|
|
|
set_buffer_mapped(bh);
|
|
|
|
clear_buffer_delay(bh);
|
2006-01-11 04:40:13 +00:00
|
|
|
clear_buffer_unwritten(bh);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-01-11 09:49:28 +00:00
|
|
|
* Look for a page at index that is suitable for clustering.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
|
|
|
STATIC unsigned int
|
2006-01-11 09:49:28 +00:00
|
|
|
xfs_probe_page(
|
2006-01-11 09:48:14 +00:00
|
|
|
struct page *page,
|
2006-01-11 09:49:28 +00:00
|
|
|
unsigned int pg_offset,
|
|
|
|
int mapped)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (PageWriteback(page))
|
2006-01-11 09:48:14 +00:00
|
|
|
return 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
if (page->mapping && PageDirty(page)) {
|
|
|
|
if (page_has_buffers(page)) {
|
|
|
|
struct buffer_head *bh, *head;
|
|
|
|
|
|
|
|
bh = head = page_buffers(page);
|
|
|
|
do {
|
2006-01-11 09:49:28 +00:00
|
|
|
if (!buffer_uptodate(bh))
|
|
|
|
break;
|
|
|
|
if (mapped != buffer_mapped(bh))
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
ret += bh->b_size;
|
|
|
|
if (ret >= pg_offset)
|
|
|
|
break;
|
|
|
|
} while ((bh = bh->b_this_page) != head);
|
|
|
|
} else
|
2006-01-11 09:49:28 +00:00
|
|
|
ret = mapped ? 0 : PAGE_CACHE_SIZE;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-01-11 04:40:13 +00:00
|
|
|
STATIC size_t
|
2006-01-11 09:49:28 +00:00
|
|
|
xfs_probe_cluster(
|
2005-04-16 22:20:36 +00:00
|
|
|
struct inode *inode,
|
|
|
|
struct page *startpage,
|
|
|
|
struct buffer_head *bh,
|
2006-01-11 09:49:28 +00:00
|
|
|
struct buffer_head *head,
|
|
|
|
int mapped)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2006-01-11 09:48:14 +00:00
|
|
|
struct pagevec pvec;
|
2005-04-16 22:20:36 +00:00
|
|
|
pgoff_t tindex, tlast, tloff;
|
2006-01-11 09:48:14 +00:00
|
|
|
size_t total = 0;
|
|
|
|
int done = 0, i;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/* First sum forwards in this page */
|
|
|
|
do {
|
2006-02-28 01:30:30 +00:00
|
|
|
if (!buffer_uptodate(bh) || (mapped != buffer_mapped(bh)))
|
2006-01-11 09:48:14 +00:00
|
|
|
return total;
|
2005-04-16 22:20:36 +00:00
|
|
|
total += bh->b_size;
|
|
|
|
} while ((bh = bh->b_this_page) != head);
|
|
|
|
|
2006-01-11 09:48:14 +00:00
|
|
|
/* if we reached the end of the page, sum forwards in following pages */
|
|
|
|
tlast = i_size_read(inode) >> PAGE_CACHE_SHIFT;
|
|
|
|
tindex = startpage->index + 1;
|
|
|
|
|
|
|
|
/* Prune this back to avoid pathological behavior */
|
|
|
|
tloff = min(tlast, startpage->index + 64);
|
|
|
|
|
|
|
|
pagevec_init(&pvec, 0);
|
|
|
|
while (!done && tindex <= tloff) {
|
|
|
|
unsigned len = min_t(pgoff_t, PAGEVEC_SIZE, tlast - tindex + 1);
|
|
|
|
|
|
|
|
if (!pagevec_lookup(&pvec, inode->i_mapping, tindex, len))
|
|
|
|
break;
|
|
|
|
|
|
|
|
for (i = 0; i < pagevec_count(&pvec); i++) {
|
|
|
|
struct page *page = pvec.pages[i];
|
2007-08-16 05:38:19 +00:00
|
|
|
size_t pg_offset, pg_len = 0;
|
2006-01-11 09:48:14 +00:00
|
|
|
|
|
|
|
if (tindex == tlast) {
|
|
|
|
pg_offset =
|
|
|
|
i_size_read(inode) & (PAGE_CACHE_SIZE - 1);
|
2006-01-11 09:48:33 +00:00
|
|
|
if (!pg_offset) {
|
|
|
|
done = 1;
|
2006-01-11 09:48:14 +00:00
|
|
|
break;
|
2006-01-11 09:48:33 +00:00
|
|
|
}
|
2006-01-11 09:48:14 +00:00
|
|
|
} else
|
|
|
|
pg_offset = PAGE_CACHE_SIZE;
|
|
|
|
|
2008-08-02 10:01:03 +00:00
|
|
|
if (page->index == tindex && trylock_page(page)) {
|
2007-08-16 05:38:19 +00:00
|
|
|
pg_len = xfs_probe_page(page, pg_offset, mapped);
|
2006-01-11 09:48:14 +00:00
|
|
|
unlock_page(page);
|
|
|
|
}
|
|
|
|
|
2007-08-16 05:38:19 +00:00
|
|
|
if (!pg_len) {
|
2006-01-11 09:48:14 +00:00
|
|
|
done = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-08-16 05:38:19 +00:00
|
|
|
total += pg_len;
|
2006-01-11 09:48:33 +00:00
|
|
|
tindex++;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2006-01-11 09:48:14 +00:00
|
|
|
|
|
|
|
pagevec_release(&pvec);
|
|
|
|
cond_resched();
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2006-01-11 09:48:14 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
return total;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-01-11 09:48:14 +00:00
|
|
|
* Test if a given page is suitable for writing as part of an unwritten
|
|
|
|
* or delayed allocate extent.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2006-01-11 09:48:14 +00:00
|
|
|
STATIC int
|
|
|
|
xfs_is_delayed_page(
|
|
|
|
struct page *page,
|
2006-01-11 04:40:13 +00:00
|
|
|
unsigned int type)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
if (PageWriteback(page))
|
2006-01-11 09:48:14 +00:00
|
|
|
return 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
if (page->mapping && page_has_buffers(page)) {
|
|
|
|
struct buffer_head *bh, *head;
|
|
|
|
int acceptable = 0;
|
|
|
|
|
|
|
|
bh = head = page_buffers(page);
|
|
|
|
do {
|
2006-01-11 04:40:13 +00:00
|
|
|
if (buffer_unwritten(bh))
|
2010-04-28 12:28:57 +00:00
|
|
|
acceptable = (type == IO_UNWRITTEN);
|
2006-01-11 04:40:13 +00:00
|
|
|
else if (buffer_delay(bh))
|
2010-04-28 12:28:57 +00:00
|
|
|
acceptable = (type == IO_DELAY);
|
2006-03-22 01:47:40 +00:00
|
|
|
else if (buffer_dirty(bh) && buffer_mapped(bh))
|
2010-04-28 12:28:57 +00:00
|
|
|
acceptable = (type == IO_NEW);
|
2006-01-11 04:40:13 +00:00
|
|
|
else
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
} while ((bh = bh->b_this_page) != head);
|
|
|
|
|
|
|
|
if (acceptable)
|
2006-01-11 09:48:14 +00:00
|
|
|
return 1;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2006-01-11 09:48:14 +00:00
|
|
|
return 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate & map buffers for page given the extent map. Write it out.
|
|
|
|
* except for the original page of a writepage, this is called on
|
|
|
|
* delalloc/unwritten pages only, for the original page it is possible
|
|
|
|
* that the page has no mapping at all.
|
|
|
|
*/
|
2006-01-11 04:40:13 +00:00
|
|
|
STATIC int
|
2005-04-16 22:20:36 +00:00
|
|
|
xfs_convert_page(
|
|
|
|
struct inode *inode,
|
|
|
|
struct page *page,
|
2006-01-11 09:48:14 +00:00
|
|
|
loff_t tindex,
|
2010-04-28 12:28:56 +00:00
|
|
|
struct xfs_bmbt_irec *imap,
|
2006-01-11 04:40:13 +00:00
|
|
|
xfs_ioend_t **ioendp,
|
2005-04-16 22:20:36 +00:00
|
|
|
struct writeback_control *wbc,
|
|
|
|
int startio,
|
|
|
|
int all_bh)
|
|
|
|
{
|
2006-01-11 04:40:13 +00:00
|
|
|
struct buffer_head *bh, *head;
|
2006-01-11 09:48:47 +00:00
|
|
|
xfs_off_t end_offset;
|
|
|
|
unsigned long p_offset;
|
2006-01-11 04:40:13 +00:00
|
|
|
unsigned int type;
|
2005-05-05 20:33:20 +00:00
|
|
|
int len, page_dirty;
|
2006-01-11 04:40:13 +00:00
|
|
|
int count = 0, done = 0, uptodate = 1;
|
2006-01-11 09:48:47 +00:00
|
|
|
xfs_off_t offset = page_offset(page);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2006-01-11 09:48:14 +00:00
|
|
|
if (page->index != tindex)
|
|
|
|
goto fail;
|
2008-08-02 10:01:03 +00:00
|
|
|
if (!trylock_page(page))
|
2006-01-11 09:48:14 +00:00
|
|
|
goto fail;
|
|
|
|
if (PageWriteback(page))
|
|
|
|
goto fail_unlock_page;
|
|
|
|
if (page->mapping != inode->i_mapping)
|
|
|
|
goto fail_unlock_page;
|
|
|
|
if (!xfs_is_delayed_page(page, (*ioendp)->io_type))
|
|
|
|
goto fail_unlock_page;
|
|
|
|
|
2005-05-05 20:33:20 +00:00
|
|
|
/*
|
|
|
|
* page_dirty is initially a count of buffers on the page before
|
2006-03-28 22:55:14 +00:00
|
|
|
* EOF and is decremented as we move each into a cleanable state.
|
2006-01-11 09:48:47 +00:00
|
|
|
*
|
|
|
|
* Derivation:
|
|
|
|
*
|
|
|
|
* End offset is the highest offset that this page should represent.
|
|
|
|
* If we are on the last page, (end_offset & (PAGE_CACHE_SIZE - 1))
|
|
|
|
* will evaluate non-zero and be less than PAGE_CACHE_SIZE and
|
|
|
|
* hence give us the correct page_dirty count. On any other page,
|
|
|
|
* it will be zero and in that case we need page_dirty to be the
|
|
|
|
* count of buffers on the page.
|
2005-05-05 20:33:20 +00:00
|
|
|
*/
|
2006-01-11 09:48:47 +00:00
|
|
|
end_offset = min_t(unsigned long long,
|
|
|
|
(xfs_off_t)(page->index + 1) << PAGE_CACHE_SHIFT,
|
|
|
|
i_size_read(inode));
|
|
|
|
|
2005-05-05 20:33:20 +00:00
|
|
|
len = 1 << inode->i_blkbits;
|
2006-01-11 09:48:47 +00:00
|
|
|
p_offset = min_t(unsigned long, end_offset & (PAGE_CACHE_SIZE - 1),
|
|
|
|
PAGE_CACHE_SIZE);
|
|
|
|
p_offset = p_offset ? roundup(p_offset, len) : PAGE_CACHE_SIZE;
|
|
|
|
page_dirty = p_offset / len;
|
2005-05-05 20:33:20 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
bh = head = page_buffers(page);
|
|
|
|
do {
|
2006-01-11 09:48:47 +00:00
|
|
|
if (offset >= end_offset)
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
2006-01-11 04:40:13 +00:00
|
|
|
if (!buffer_uptodate(bh))
|
|
|
|
uptodate = 0;
|
|
|
|
if (!(PageUptodate(page) || buffer_uptodate(bh))) {
|
|
|
|
done = 1;
|
2005-04-16 22:20:36 +00:00
|
|
|
continue;
|
2006-01-11 04:40:13 +00:00
|
|
|
}
|
|
|
|
|
2006-01-11 09:48:47 +00:00
|
|
|
if (buffer_unwritten(bh) || buffer_delay(bh)) {
|
|
|
|
if (buffer_unwritten(bh))
|
2010-04-28 12:28:57 +00:00
|
|
|
type = IO_UNWRITTEN;
|
2006-01-11 09:48:47 +00:00
|
|
|
else
|
2010-04-28 12:28:57 +00:00
|
|
|
type = IO_DELAY;
|
2006-01-11 09:48:47 +00:00
|
|
|
|
2010-04-28 12:28:58 +00:00
|
|
|
if (!xfs_imap_valid(inode, imap, offset)) {
|
2006-01-11 04:40:13 +00:00
|
|
|
done = 1;
|
2006-01-11 09:48:47 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-04-28 12:28:56 +00:00
|
|
|
ASSERT(imap->br_startblock != HOLESTARTBLOCK);
|
|
|
|
ASSERT(imap->br_startblock != DELAYSTARTBLOCK);
|
2006-01-11 09:48:47 +00:00
|
|
|
|
2010-04-28 12:28:56 +00:00
|
|
|
xfs_map_at_offset(inode, bh, imap, offset);
|
2006-01-11 09:48:47 +00:00
|
|
|
if (startio) {
|
2006-01-11 09:49:16 +00:00
|
|
|
xfs_add_to_ioend(inode, bh, offset,
|
2006-01-11 09:48:47 +00:00
|
|
|
type, ioendp, done);
|
|
|
|
} else {
|
|
|
|
set_buffer_dirty(bh);
|
|
|
|
unlock_buffer(bh);
|
|
|
|
mark_buffer_dirty(bh);
|
|
|
|
}
|
|
|
|
page_dirty--;
|
|
|
|
count++;
|
|
|
|
} else {
|
2010-04-28 12:28:57 +00:00
|
|
|
type = IO_NEW;
|
2006-01-11 09:48:47 +00:00
|
|
|
if (buffer_mapped(bh) && all_bh && startio) {
|
2005-04-16 22:20:36 +00:00
|
|
|
lock_buffer(bh);
|
2006-01-11 09:49:16 +00:00
|
|
|
xfs_add_to_ioend(inode, bh, offset,
|
2006-01-11 04:40:13 +00:00
|
|
|
type, ioendp, done);
|
|
|
|
count++;
|
2005-05-05 20:33:20 +00:00
|
|
|
page_dirty--;
|
2006-01-11 09:48:47 +00:00
|
|
|
} else {
|
|
|
|
done = 1;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
2006-01-11 09:49:16 +00:00
|
|
|
} while (offset += len, (bh = bh->b_this_page) != head);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2006-01-11 04:40:13 +00:00
|
|
|
if (uptodate && bh == head)
|
|
|
|
SetPageUptodate(page);
|
|
|
|
|
|
|
|
if (startio) {
|
2006-01-11 09:49:42 +00:00
|
|
|
if (count) {
|
2006-02-07 09:27:24 +00:00
|
|
|
wbc->nr_to_write--;
|
2009-12-03 12:54:25 +00:00
|
|
|
if (wbc->nr_to_write <= 0)
|
2006-01-11 09:49:42 +00:00
|
|
|
done = 1;
|
|
|
|
}
|
2008-05-19 06:34:11 +00:00
|
|
|
xfs_start_page_writeback(page, !page_dirty, count);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2006-01-11 04:40:13 +00:00
|
|
|
|
|
|
|
return done;
|
2006-01-11 09:48:14 +00:00
|
|
|
fail_unlock_page:
|
|
|
|
unlock_page(page);
|
|
|
|
fail:
|
|
|
|
return 1;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert & write out a cluster of pages in the same extent as defined
|
|
|
|
* by mp and following the start page.
|
|
|
|
*/
|
|
|
|
STATIC void
|
|
|
|
xfs_cluster_write(
|
|
|
|
struct inode *inode,
|
|
|
|
pgoff_t tindex,
|
2010-04-28 12:28:56 +00:00
|
|
|
struct xfs_bmbt_irec *imap,
|
2006-01-11 04:40:13 +00:00
|
|
|
xfs_ioend_t **ioendp,
|
2005-04-16 22:20:36 +00:00
|
|
|
struct writeback_control *wbc,
|
|
|
|
int startio,
|
|
|
|
int all_bh,
|
|
|
|
pgoff_t tlast)
|
|
|
|
{
|
2006-01-11 09:48:14 +00:00
|
|
|
struct pagevec pvec;
|
|
|
|
int done = 0, i;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2006-01-11 09:48:14 +00:00
|
|
|
pagevec_init(&pvec, 0);
|
|
|
|
while (!done && tindex <= tlast) {
|
|
|
|
unsigned len = min_t(pgoff_t, PAGEVEC_SIZE, tlast - tindex + 1);
|
|
|
|
|
|
|
|
if (!pagevec_lookup(&pvec, inode->i_mapping, tindex, len))
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
2006-01-11 09:48:14 +00:00
|
|
|
|
|
|
|
for (i = 0; i < pagevec_count(&pvec); i++) {
|
|
|
|
done = xfs_convert_page(inode, pvec.pages[i], tindex++,
|
2010-04-28 12:28:56 +00:00
|
|
|
imap, ioendp, wbc, startio, all_bh);
|
2006-01-11 09:48:14 +00:00
|
|
|
if (done)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pagevec_release(&pvec);
|
|
|
|
cond_resched();
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-05 02:00:42 +00:00
|
|
|
STATIC void
|
|
|
|
xfs_vm_invalidatepage(
|
|
|
|
struct page *page,
|
|
|
|
unsigned long offset)
|
|
|
|
{
|
|
|
|
trace_xfs_invalidatepage(page->mapping->host, page, offset);
|
|
|
|
block_invalidatepage(page, offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the page has delalloc buffers on it, we need to punch them out before we
|
|
|
|
* invalidate the page. If we don't, we leave a stale delalloc mapping on the
|
|
|
|
* inode that can trip a BUG() in xfs_get_blocks() later on if a direct IO read
|
|
|
|
* is done on that same region - the delalloc extent is returned when none is
|
|
|
|
* supposed to be there.
|
|
|
|
*
|
|
|
|
* We prevent this by truncating away the delalloc regions on the page before
|
|
|
|
* invalidating it. Because they are delalloc, we can do this without needing a
|
|
|
|
* transaction. Indeed - if we get ENOSPC errors, we have to be able to do this
|
|
|
|
* truncation without a transaction as there is no space left for block
|
|
|
|
* reservation (typically why we see a ENOSPC in writeback).
|
|
|
|
*
|
|
|
|
* This is not a performance critical path, so for now just do the punching a
|
|
|
|
* buffer head at a time.
|
|
|
|
*/
|
|
|
|
STATIC void
|
|
|
|
xfs_aops_discard_page(
|
|
|
|
struct page *page)
|
|
|
|
{
|
|
|
|
struct inode *inode = page->mapping->host;
|
|
|
|
struct xfs_inode *ip = XFS_I(inode);
|
|
|
|
struct buffer_head *bh, *head;
|
|
|
|
loff_t offset = page_offset(page);
|
|
|
|
ssize_t len = 1 << inode->i_blkbits;
|
|
|
|
|
2010-04-28 12:28:57 +00:00
|
|
|
if (!xfs_is_delayed_page(page, IO_DELAY))
|
2010-03-05 02:00:42 +00:00
|
|
|
goto out_invalidate;
|
|
|
|
|
2010-03-15 02:36:35 +00:00
|
|
|
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
|
|
|
|
goto out_invalidate;
|
|
|
|
|
2010-03-05 02:00:42 +00:00
|
|
|
xfs_fs_cmn_err(CE_ALERT, ip->i_mount,
|
|
|
|
"page discard on page %p, inode 0x%llx, offset %llu.",
|
|
|
|
page, ip->i_ino, offset);
|
|
|
|
|
|
|
|
xfs_ilock(ip, XFS_ILOCK_EXCL);
|
|
|
|
bh = head = page_buffers(page);
|
|
|
|
do {
|
|
|
|
int done;
|
|
|
|
xfs_fileoff_t offset_fsb;
|
|
|
|
xfs_bmbt_irec_t imap;
|
|
|
|
int nimaps = 1;
|
|
|
|
int error;
|
|
|
|
xfs_fsblock_t firstblock;
|
|
|
|
xfs_bmap_free_t flist;
|
|
|
|
|
|
|
|
if (!buffer_delay(bh))
|
|
|
|
goto next_buffer;
|
|
|
|
|
|
|
|
offset_fsb = XFS_B_TO_FSBT(ip->i_mount, offset);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Map the range first and check that it is a delalloc extent
|
|
|
|
* before trying to unmap the range. Otherwise we will be
|
|
|
|
* trying to remove a real extent (which requires a
|
|
|
|
* transaction) or a hole, which is probably a bad idea...
|
|
|
|
*/
|
|
|
|
error = xfs_bmapi(NULL, ip, offset_fsb, 1,
|
|
|
|
XFS_BMAPI_ENTIRE, NULL, 0, &imap,
|
|
|
|
&nimaps, NULL, NULL);
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
/* something screwed, just bail */
|
2010-03-15 02:36:35 +00:00
|
|
|
if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
|
|
|
|
xfs_fs_cmn_err(CE_ALERT, ip->i_mount,
|
|
|
|
"page discard failed delalloc mapping lookup.");
|
|
|
|
}
|
2010-03-05 02:00:42 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!nimaps) {
|
|
|
|
/* nothing there */
|
|
|
|
goto next_buffer;
|
|
|
|
}
|
|
|
|
if (imap.br_startblock != DELAYSTARTBLOCK) {
|
|
|
|
/* been converted, ignore */
|
|
|
|
goto next_buffer;
|
|
|
|
}
|
|
|
|
WARN_ON(imap.br_blockcount == 0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note: while we initialise the firstblock/flist pair, they
|
|
|
|
* should never be used because blocks should never be
|
|
|
|
* allocated or freed for a delalloc extent and hence we need
|
|
|
|
* don't cancel or finish them after the xfs_bunmapi() call.
|
|
|
|
*/
|
|
|
|
xfs_bmap_init(&flist, &firstblock);
|
|
|
|
error = xfs_bunmapi(NULL, ip, offset_fsb, 1, 0, 1, &firstblock,
|
|
|
|
&flist, NULL, &done);
|
|
|
|
|
|
|
|
ASSERT(!flist.xbf_count && !flist.xbf_first);
|
|
|
|
if (error) {
|
|
|
|
/* something screwed, just bail */
|
2010-03-15 02:36:35 +00:00
|
|
|
if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
|
|
|
|
xfs_fs_cmn_err(CE_ALERT, ip->i_mount,
|
2010-03-05 02:00:42 +00:00
|
|
|
"page discard unable to remove delalloc mapping.");
|
2010-03-15 02:36:35 +00:00
|
|
|
}
|
2010-03-05 02:00:42 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
next_buffer:
|
|
|
|
offset += len;
|
|
|
|
|
|
|
|
} while ((bh = bh->b_this_page) != head);
|
|
|
|
|
|
|
|
xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
|
|
|
out_invalidate:
|
|
|
|
xfs_vm_invalidatepage(page, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* Calling this without startio set means we are being asked to make a dirty
|
|
|
|
* page ready for freeing it's buffers. When called with startio set then
|
|
|
|
* we are coming from writepage.
|
|
|
|
*
|
|
|
|
* When called with startio set it is important that we write the WHOLE
|
|
|
|
* page if possible.
|
|
|
|
* The bh->b_state's cannot know if any of the blocks or which block for
|
|
|
|
* that matter are dirty due to mmap writes, and therefore bh uptodate is
|
2006-03-28 22:55:14 +00:00
|
|
|
* only valid if the page itself isn't completely uptodate. Some layers
|
2005-04-16 22:20:36 +00:00
|
|
|
* may clear the page dirty flag prior to calling write page, under the
|
|
|
|
* assumption the entire page will be written out; by not writing out the
|
|
|
|
* whole page the page can be reused before all valid dirty data is
|
|
|
|
* written out. Note: in the case of a page that has been dirty'd by
|
|
|
|
* mapwrite and but partially setup by block_prepare_write the
|
|
|
|
* bh->b_states's will not agree and only ones setup by BPW/BCW will have
|
|
|
|
* valid state, thus the whole page must be written out thing.
|
|
|
|
*/
|
|
|
|
|
|
|
|
STATIC int
|
|
|
|
xfs_page_state_convert(
|
|
|
|
struct inode *inode,
|
|
|
|
struct page *page,
|
|
|
|
struct writeback_control *wbc,
|
|
|
|
int startio,
|
|
|
|
int unmapped) /* also implies page uptodate */
|
|
|
|
{
|
2006-01-11 04:40:13 +00:00
|
|
|
struct buffer_head *bh, *head;
|
2010-04-28 12:28:56 +00:00
|
|
|
struct xfs_bmbt_irec imap;
|
2006-01-11 04:40:13 +00:00
|
|
|
xfs_ioend_t *ioend = NULL, *iohead = NULL;
|
2005-04-16 22:20:36 +00:00
|
|
|
loff_t offset;
|
|
|
|
unsigned long p_offset = 0;
|
2006-01-11 04:40:13 +00:00
|
|
|
unsigned int type;
|
2005-04-16 22:20:36 +00:00
|
|
|
__uint64_t end_offset;
|
2010-04-28 12:29:00 +00:00
|
|
|
pgoff_t end_index, last_index;
|
2006-01-11 09:49:02 +00:00
|
|
|
ssize_t size, len;
|
2010-04-28 12:28:58 +00:00
|
|
|
int flags, err, imap_valid = 0, uptodate = 1;
|
2006-04-11 05:10:55 +00:00
|
|
|
int page_dirty, count = 0;
|
|
|
|
int trylock = 0;
|
2006-01-11 09:49:28 +00:00
|
|
|
int all_bh = unmapped;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2006-04-11 05:10:55 +00:00
|
|
|
if (startio) {
|
|
|
|
if (wbc->sync_mode == WB_SYNC_NONE && wbc->nonblocking)
|
|
|
|
trylock |= BMAPI_TRYLOCK;
|
|
|
|
}
|
2005-05-05 20:31:34 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/* Is this page beyond the end of the file? */
|
|
|
|
offset = i_size_read(inode);
|
|
|
|
end_index = offset >> PAGE_CACHE_SHIFT;
|
|
|
|
last_index = (offset - 1) >> PAGE_CACHE_SHIFT;
|
|
|
|
if (page->index >= end_index) {
|
|
|
|
if ((page->index >= end_index + 1) ||
|
|
|
|
!(i_size_read(inode) & (PAGE_CACHE_SIZE - 1))) {
|
2005-11-02 04:14:09 +00:00
|
|
|
if (startio)
|
|
|
|
unlock_page(page);
|
|
|
|
return 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-05-05 20:33:20 +00:00
|
|
|
* page_dirty is initially a count of buffers on the page before
|
2006-03-28 22:55:14 +00:00
|
|
|
* EOF and is decremented as we move each into a cleanable state.
|
2006-01-11 04:40:13 +00:00
|
|
|
*
|
|
|
|
* Derivation:
|
|
|
|
*
|
|
|
|
* End offset is the highest offset that this page should represent.
|
|
|
|
* If we are on the last page, (end_offset & (PAGE_CACHE_SIZE - 1))
|
|
|
|
* will evaluate non-zero and be less than PAGE_CACHE_SIZE and
|
|
|
|
* hence give us the correct page_dirty count. On any other page,
|
|
|
|
* it will be zero and in that case we need page_dirty to be the
|
|
|
|
* count of buffers on the page.
|
|
|
|
*/
|
|
|
|
end_offset = min_t(unsigned long long,
|
|
|
|
(xfs_off_t)(page->index + 1) << PAGE_CACHE_SHIFT, offset);
|
2005-05-05 20:33:20 +00:00
|
|
|
len = 1 << inode->i_blkbits;
|
2006-01-11 04:40:13 +00:00
|
|
|
p_offset = min_t(unsigned long, end_offset & (PAGE_CACHE_SIZE - 1),
|
|
|
|
PAGE_CACHE_SIZE);
|
|
|
|
p_offset = p_offset ? roundup(p_offset, len) : PAGE_CACHE_SIZE;
|
2005-05-05 20:33:20 +00:00
|
|
|
page_dirty = p_offset / len;
|
|
|
|
|
|
|
|
bh = head = page_buffers(page);
|
2006-01-11 04:40:13 +00:00
|
|
|
offset = page_offset(page);
|
2007-05-24 05:27:03 +00:00
|
|
|
flags = BMAPI_READ;
|
2010-04-28 12:28:57 +00:00
|
|
|
type = IO_NEW;
|
2006-01-11 04:40:13 +00:00
|
|
|
|
|
|
|
/* TODO: cleanup count and page_dirty */
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
if (offset >= end_offset)
|
|
|
|
break;
|
|
|
|
if (!buffer_uptodate(bh))
|
|
|
|
uptodate = 0;
|
2006-01-11 04:40:13 +00:00
|
|
|
if (!(PageUptodate(page) || buffer_uptodate(bh)) && !startio) {
|
2006-01-11 09:48:33 +00:00
|
|
|
/*
|
|
|
|
* the iomap is actually still valid, but the ioend
|
|
|
|
* isn't. shouldn't happen too often.
|
|
|
|
*/
|
2010-04-28 12:28:58 +00:00
|
|
|
imap_valid = 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
continue;
|
2006-01-11 04:40:13 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2010-04-28 12:28:58 +00:00
|
|
|
if (imap_valid)
|
|
|
|
imap_valid = xfs_imap_valid(inode, &imap, offset);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* First case, map an unwritten extent and prepare for
|
|
|
|
* extent state conversion transaction on completion.
|
2006-01-11 04:40:13 +00:00
|
|
|
*
|
2005-04-16 22:20:36 +00:00
|
|
|
* Second case, allocate space for a delalloc buffer.
|
|
|
|
* We can return EAGAIN here in the release page case.
|
2006-01-11 09:49:02 +00:00
|
|
|
*
|
|
|
|
* Third case, an unmapped buffer was found, and we are
|
|
|
|
* in a path where we need to write the whole page out.
|
2007-05-24 05:27:03 +00:00
|
|
|
*/
|
2006-01-11 09:49:02 +00:00
|
|
|
if (buffer_unwritten(bh) || buffer_delay(bh) ||
|
|
|
|
((buffer_uptodate(bh) || PageUptodate(page)) &&
|
|
|
|
!buffer_mapped(bh) && (unmapped || startio))) {
|
2007-06-18 06:49:58 +00:00
|
|
|
int new_ioend = 0;
|
|
|
|
|
2007-05-24 05:27:03 +00:00
|
|
|
/*
|
2006-01-11 09:49:28 +00:00
|
|
|
* Make sure we don't use a read-only iomap
|
|
|
|
*/
|
2007-05-24 05:27:03 +00:00
|
|
|
if (flags == BMAPI_READ)
|
2010-04-28 12:28:58 +00:00
|
|
|
imap_valid = 0;
|
2006-01-11 09:49:28 +00:00
|
|
|
|
2006-01-11 04:40:13 +00:00
|
|
|
if (buffer_unwritten(bh)) {
|
2010-04-28 12:28:57 +00:00
|
|
|
type = IO_UNWRITTEN;
|
2006-04-11 05:10:55 +00:00
|
|
|
flags = BMAPI_WRITE | BMAPI_IGNSTATE;
|
2006-01-11 09:49:02 +00:00
|
|
|
} else if (buffer_delay(bh)) {
|
2010-04-28 12:28:57 +00:00
|
|
|
type = IO_DELAY;
|
2006-04-11 05:10:55 +00:00
|
|
|
flags = BMAPI_ALLOCATE | trylock;
|
2006-01-11 09:49:02 +00:00
|
|
|
} else {
|
2010-04-28 12:28:57 +00:00
|
|
|
type = IO_NEW;
|
2006-04-11 05:10:55 +00:00
|
|
|
flags = BMAPI_WRITE | BMAPI_MMAP;
|
2006-01-11 04:40:13 +00:00
|
|
|
}
|
|
|
|
|
2010-04-28 12:28:58 +00:00
|
|
|
if (!imap_valid) {
|
2007-06-18 06:49:58 +00:00
|
|
|
/*
|
|
|
|
* if we didn't have a valid mapping then we
|
|
|
|
* need to ensure that we put the new mapping
|
|
|
|
* in a new ioend structure. This needs to be
|
|
|
|
* done to ensure that the ioends correctly
|
|
|
|
* reflect the block mappings at io completion
|
|
|
|
* for unwritten extent conversion.
|
|
|
|
*/
|
|
|
|
new_ioend = 1;
|
2010-04-28 12:28:57 +00:00
|
|
|
if (type == IO_NEW) {
|
2006-01-11 09:49:28 +00:00
|
|
|
size = xfs_probe_cluster(inode,
|
|
|
|
page, bh, head, 0);
|
2006-01-11 09:49:02 +00:00
|
|
|
} else {
|
|
|
|
size = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = xfs_map_blocks(inode, offset, size,
|
2010-04-28 12:28:56 +00:00
|
|
|
&imap, flags);
|
2006-01-11 04:40:13 +00:00
|
|
|
if (err)
|
2005-04-16 22:20:36 +00:00
|
|
|
goto error;
|
2010-04-28 12:28:58 +00:00
|
|
|
imap_valid = xfs_imap_valid(inode, &imap,
|
|
|
|
offset);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2010-04-28 12:28:58 +00:00
|
|
|
if (imap_valid) {
|
2010-04-28 12:28:56 +00:00
|
|
|
xfs_map_at_offset(inode, bh, &imap, offset);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (startio) {
|
2006-01-11 09:49:16 +00:00
|
|
|
xfs_add_to_ioend(inode, bh, offset,
|
2006-01-11 09:48:33 +00:00
|
|
|
type, &ioend,
|
2007-06-18 06:49:58 +00:00
|
|
|
new_ioend);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
|
|
|
set_buffer_dirty(bh);
|
|
|
|
unlock_buffer(bh);
|
|
|
|
mark_buffer_dirty(bh);
|
|
|
|
}
|
|
|
|
page_dirty--;
|
2006-01-11 04:40:13 +00:00
|
|
|
count++;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2006-01-11 09:49:02 +00:00
|
|
|
} else if (buffer_uptodate(bh) && startio) {
|
2006-01-11 09:49:28 +00:00
|
|
|
/*
|
|
|
|
* we got here because the buffer is already mapped.
|
|
|
|
* That means it must already have extents allocated
|
|
|
|
* underneath it. Map the extent by reading it.
|
|
|
|
*/
|
2010-04-28 12:28:58 +00:00
|
|
|
if (!imap_valid || flags != BMAPI_READ) {
|
2006-01-11 09:49:28 +00:00
|
|
|
flags = BMAPI_READ;
|
|
|
|
size = xfs_probe_cluster(inode, page, bh,
|
|
|
|
head, 1);
|
|
|
|
err = xfs_map_blocks(inode, offset, size,
|
2010-04-28 12:28:56 +00:00
|
|
|
&imap, flags);
|
2006-01-11 09:49:28 +00:00
|
|
|
if (err)
|
|
|
|
goto error;
|
2010-04-28 12:28:58 +00:00
|
|
|
imap_valid = xfs_imap_valid(inode, &imap,
|
|
|
|
offset);
|
2006-01-11 09:49:28 +00:00
|
|
|
}
|
2006-01-11 09:49:02 +00:00
|
|
|
|
2007-05-24 05:27:03 +00:00
|
|
|
/*
|
2010-04-28 12:28:57 +00:00
|
|
|
* We set the type to IO_NEW in case we are doing a
|
2007-05-24 05:27:03 +00:00
|
|
|
* small write at EOF that is extending the file but
|
|
|
|
* without needing an allocation. We need to update the
|
|
|
|
* file size on I/O completion in this case so it is
|
|
|
|
* the same case as having just allocated a new extent
|
|
|
|
* that we are writing into for the first time.
|
|
|
|
*/
|
2010-04-28 12:28:57 +00:00
|
|
|
type = IO_NEW;
|
2008-08-02 10:02:13 +00:00
|
|
|
if (trylock_buffer(bh)) {
|
2006-01-11 09:49:02 +00:00
|
|
|
ASSERT(buffer_mapped(bh));
|
2010-04-28 12:28:58 +00:00
|
|
|
if (imap_valid)
|
2006-01-11 09:49:28 +00:00
|
|
|
all_bh = 1;
|
2006-01-11 09:49:16 +00:00
|
|
|
xfs_add_to_ioend(inode, bh, offset, type,
|
2010-04-28 12:28:58 +00:00
|
|
|
&ioend, !imap_valid);
|
2006-01-11 09:49:02 +00:00
|
|
|
page_dirty--;
|
|
|
|
count++;
|
2006-01-11 04:40:13 +00:00
|
|
|
} else {
|
2010-04-28 12:28:58 +00:00
|
|
|
imap_valid = 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2006-01-11 09:49:02 +00:00
|
|
|
} else if ((buffer_uptodate(bh) || PageUptodate(page)) &&
|
|
|
|
(unmapped || startio)) {
|
2010-04-28 12:28:58 +00:00
|
|
|
imap_valid = 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2006-01-11 04:40:13 +00:00
|
|
|
|
|
|
|
if (!iohead)
|
|
|
|
iohead = ioend;
|
|
|
|
|
|
|
|
} while (offset += len, ((bh = bh->b_this_page) != head));
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
if (uptodate && bh == head)
|
|
|
|
SetPageUptodate(page);
|
|
|
|
|
2006-01-11 04:40:13 +00:00
|
|
|
if (startio)
|
2008-05-19 06:34:11 +00:00
|
|
|
xfs_start_page_writeback(page, 1, count);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2010-04-28 12:28:58 +00:00
|
|
|
if (ioend && imap_valid) {
|
2010-04-28 12:29:00 +00:00
|
|
|
xfs_off_t end_index;
|
|
|
|
|
|
|
|
end_index = imap.br_startoff + imap.br_blockcount;
|
|
|
|
|
|
|
|
/* to bytes */
|
|
|
|
end_index <<= inode->i_blkbits;
|
|
|
|
|
|
|
|
/* to pages */
|
|
|
|
end_index = (end_index - 1) >> PAGE_CACHE_SHIFT;
|
|
|
|
|
|
|
|
/* check against file size */
|
|
|
|
if (end_index > last_index)
|
|
|
|
end_index = last_index;
|
2010-04-28 12:28:54 +00:00
|
|
|
|
2010-04-28 12:28:56 +00:00
|
|
|
xfs_cluster_write(inode, page->index + 1, &imap, &ioend,
|
2010-04-28 12:29:00 +00:00
|
|
|
wbc, startio, all_bh, end_index);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2006-01-11 04:40:13 +00:00
|
|
|
if (iohead)
|
2009-10-30 09:09:15 +00:00
|
|
|
xfs_submit_ioend(wbc, iohead);
|
2006-01-11 04:40:13 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
return page_dirty;
|
|
|
|
|
|
|
|
error:
|
2006-01-11 04:40:13 +00:00
|
|
|
if (iohead)
|
|
|
|
xfs_cancel_ioend(iohead);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If it's delalloc and we have nowhere to put it,
|
|
|
|
* throw it away, unless the lower layers told
|
|
|
|
* us to try again.
|
|
|
|
*/
|
|
|
|
if (err != -EAGAIN) {
|
2006-01-11 04:40:13 +00:00
|
|
|
if (!unmapped)
|
2010-03-05 02:00:42 +00:00
|
|
|
xfs_aops_discard_page(page);
|
2005-04-16 22:20:36 +00:00
|
|
|
ClearPageUptodate(page);
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2006-03-14 02:26:27 +00:00
|
|
|
/*
|
|
|
|
* writepage: Called from one of two places:
|
|
|
|
*
|
|
|
|
* 1. we are flushing a delalloc buffer head.
|
|
|
|
*
|
|
|
|
* 2. we are writing out a dirty page. Typically the page dirty
|
|
|
|
* state is cleared before we get here. In this case is it
|
|
|
|
* conceivable we have no buffer heads.
|
|
|
|
*
|
|
|
|
* For delalloc space on the page we need to allocate space and
|
|
|
|
* flush it. For unmapped buffer heads on the page we should
|
|
|
|
* allocate space if the page is uptodate. For any other dirty
|
|
|
|
* buffer heads on the page we should flush them.
|
|
|
|
*
|
|
|
|
* If we detect that a transaction would be required to flush
|
|
|
|
* the page, we have to check the process flags first, if we
|
|
|
|
* are already in a transaction or disk I/O during allocations
|
|
|
|
* is off, we need to fail the writepage and redirty the page.
|
|
|
|
*/
|
|
|
|
|
|
|
|
STATIC int
|
2006-03-14 02:54:26 +00:00
|
|
|
xfs_vm_writepage(
|
2006-03-14 02:26:27 +00:00
|
|
|
struct page *page,
|
|
|
|
struct writeback_control *wbc)
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
int need_trans;
|
|
|
|
int delalloc, unmapped, unwritten;
|
|
|
|
struct inode *inode = page->mapping->host;
|
|
|
|
|
2009-12-14 23:14:59 +00:00
|
|
|
trace_xfs_writepage(inode, page, 0);
|
2006-03-14 02:26:27 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We need a transaction if:
|
|
|
|
* 1. There are delalloc buffers on the page
|
|
|
|
* 2. The page is uptodate and we have unmapped buffers
|
|
|
|
* 3. The page is uptodate and we have no buffers
|
|
|
|
* 4. There are unwritten buffers on the page
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!page_has_buffers(page)) {
|
|
|
|
unmapped = 1;
|
|
|
|
need_trans = 1;
|
|
|
|
} else {
|
|
|
|
xfs_count_page_state(page, &delalloc, &unmapped, &unwritten);
|
|
|
|
if (!PageUptodate(page))
|
|
|
|
unmapped = 0;
|
|
|
|
need_trans = delalloc + unmapped + unwritten;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we need a transaction and the process flags say
|
|
|
|
* we are already in a transaction, or no IO is allowed
|
|
|
|
* then mark the page dirty again and leave the page
|
|
|
|
* as is.
|
|
|
|
*/
|
2006-06-09 04:59:13 +00:00
|
|
|
if (current_test_flags(PF_FSTRANS) && need_trans)
|
2006-03-14 02:26:27 +00:00
|
|
|
goto out_fail;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delay hooking up buffer heads until we have
|
|
|
|
* made our go/no-go decision.
|
|
|
|
*/
|
|
|
|
if (!page_has_buffers(page))
|
|
|
|
create_empty_buffers(page, 1 << inode->i_blkbits, 0);
|
|
|
|
|
2009-07-31 05:02:17 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* VM calculation for nr_to_write seems off. Bump it way
|
|
|
|
* up, this gets simple streaming writes zippy again.
|
|
|
|
* To be reviewed again after Jens' writeback changes.
|
|
|
|
*/
|
|
|
|
wbc->nr_to_write *= 4;
|
|
|
|
|
2006-03-14 02:26:27 +00:00
|
|
|
/*
|
|
|
|
* Convert delayed allocate, unwritten or unmapped space
|
|
|
|
* to real space and flush out to disk.
|
|
|
|
*/
|
|
|
|
error = xfs_page_state_convert(inode, page, wbc, 1, unmapped);
|
|
|
|
if (error == -EAGAIN)
|
|
|
|
goto out_fail;
|
|
|
|
if (unlikely(error < 0))
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
out_fail:
|
|
|
|
redirty_page_for_writepage(wbc, page);
|
|
|
|
unlock_page(page);
|
|
|
|
return 0;
|
|
|
|
out_unlock:
|
|
|
|
unlock_page(page);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2006-06-09 05:27:16 +00:00
|
|
|
STATIC int
|
|
|
|
xfs_vm_writepages(
|
|
|
|
struct address_space *mapping,
|
|
|
|
struct writeback_control *wbc)
|
|
|
|
{
|
2007-08-29 01:44:37 +00:00
|
|
|
xfs_iflags_clear(XFS_I(mapping->host), XFS_ITRUNCATED);
|
2006-06-09 05:27:16 +00:00
|
|
|
return generic_writepages(mapping, wbc);
|
|
|
|
}
|
|
|
|
|
2006-03-14 02:26:27 +00:00
|
|
|
/*
|
|
|
|
* Called to move a page into cleanable state - and from there
|
|
|
|
* to be released. Possibly the page is already clean. We always
|
|
|
|
* have buffer heads in this call.
|
|
|
|
*
|
|
|
|
* Returns 0 if the page is ok to release, 1 otherwise.
|
|
|
|
*
|
|
|
|
* Possible scenarios are:
|
|
|
|
*
|
|
|
|
* 1. We are being called to release a page which has been written
|
|
|
|
* to via regular I/O. buffer heads will be dirty and possibly
|
|
|
|
* delalloc. If no delalloc buffer heads in this case then we
|
|
|
|
* can just return zero.
|
|
|
|
*
|
|
|
|
* 2. We are called to release a page which has been written via
|
|
|
|
* mmap, all we need to do is ensure there is no delalloc
|
|
|
|
* state in the buffer heads, if not we can let the caller
|
|
|
|
* free them and we should come back later via writepage.
|
|
|
|
*/
|
|
|
|
STATIC int
|
2006-03-17 06:26:25 +00:00
|
|
|
xfs_vm_releasepage(
|
2006-03-14 02:26:27 +00:00
|
|
|
struct page *page,
|
|
|
|
gfp_t gfp_mask)
|
|
|
|
{
|
|
|
|
struct inode *inode = page->mapping->host;
|
|
|
|
int dirty, delalloc, unmapped, unwritten;
|
|
|
|
struct writeback_control wbc = {
|
|
|
|
.sync_mode = WB_SYNC_ALL,
|
|
|
|
.nr_to_write = 1,
|
|
|
|
};
|
|
|
|
|
2009-12-14 23:14:59 +00:00
|
|
|
trace_xfs_releasepage(inode, page, 0);
|
2006-03-14 02:26:27 +00:00
|
|
|
|
2006-03-17 06:26:25 +00:00
|
|
|
if (!page_has_buffers(page))
|
|
|
|
return 0;
|
|
|
|
|
2006-03-14 02:26:27 +00:00
|
|
|
xfs_count_page_state(page, &delalloc, &unmapped, &unwritten);
|
|
|
|
if (!delalloc && !unwritten)
|
|
|
|
goto free_buffers;
|
|
|
|
|
|
|
|
if (!(gfp_mask & __GFP_FS))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* If we are already inside a transaction or the thread cannot
|
|
|
|
* do I/O, we cannot release this page.
|
|
|
|
*/
|
2006-06-09 04:59:13 +00:00
|
|
|
if (current_test_flags(PF_FSTRANS))
|
2006-03-14 02:26:27 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert delalloc space to real space, do not flush the
|
|
|
|
* data out to disk, that will be done by the caller.
|
|
|
|
* Never need to allocate space here - we will always
|
|
|
|
* come back to writepage in that case.
|
|
|
|
*/
|
|
|
|
dirty = xfs_page_state_convert(inode, page, &wbc, 0, 0);
|
|
|
|
if (dirty == 0 && !unwritten)
|
|
|
|
goto free_buffers;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
free_buffers:
|
|
|
|
return try_to_free_buffers(page);
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
STATIC int
|
2006-03-29 00:44:40 +00:00
|
|
|
__xfs_get_blocks(
|
2005-04-16 22:20:36 +00:00
|
|
|
struct inode *inode,
|
|
|
|
sector_t iblock,
|
|
|
|
struct buffer_head *bh_result,
|
|
|
|
int create,
|
|
|
|
int direct,
|
|
|
|
bmapi_flags_t flags)
|
|
|
|
{
|
2010-04-28 12:28:56 +00:00
|
|
|
struct xfs_bmbt_irec imap;
|
2005-11-02 04:13:13 +00:00
|
|
|
xfs_off_t offset;
|
|
|
|
ssize_t size;
|
2010-04-28 12:28:56 +00:00
|
|
|
int nimap = 1;
|
|
|
|
int new = 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
int error;
|
|
|
|
|
2005-11-02 04:13:13 +00:00
|
|
|
offset = (xfs_off_t)iblock << inode->i_blkbits;
|
2006-03-29 00:44:40 +00:00
|
|
|
ASSERT(bh_result->b_size >= (1 << inode->i_blkbits));
|
|
|
|
size = bh_result->b_size;
|
2008-09-17 06:50:14 +00:00
|
|
|
|
|
|
|
if (!create && direct && offset >= i_size_read(inode))
|
|
|
|
return 0;
|
|
|
|
|
2007-10-11 07:34:33 +00:00
|
|
|
error = xfs_iomap(XFS_I(inode), offset, size,
|
2010-04-28 12:28:56 +00:00
|
|
|
create ? flags : BMAPI_READ, &imap, &nimap, &new);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (error)
|
|
|
|
return -error;
|
2010-04-28 12:28:56 +00:00
|
|
|
if (nimap == 0)
|
2005-04-16 22:20:36 +00:00
|
|
|
return 0;
|
|
|
|
|
2010-04-28 12:28:56 +00:00
|
|
|
if (imap.br_startblock != HOLESTARTBLOCK &&
|
|
|
|
imap.br_startblock != DELAYSTARTBLOCK) {
|
2006-03-14 02:26:43 +00:00
|
|
|
/*
|
|
|
|
* For unwritten extents do not report a disk address on
|
2005-04-16 22:20:36 +00:00
|
|
|
* the read case (treat as if we're reading into a hole).
|
|
|
|
*/
|
2010-04-28 12:28:56 +00:00
|
|
|
if (create || !ISUNWRITTEN(&imap))
|
|
|
|
xfs_map_buffer(inode, bh_result, &imap, offset);
|
|
|
|
if (create && ISUNWRITTEN(&imap)) {
|
2005-04-16 22:20:36 +00:00
|
|
|
if (direct)
|
|
|
|
bh_result->b_private = inode;
|
|
|
|
set_buffer_unwritten(bh_result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-29 00:44:40 +00:00
|
|
|
/*
|
|
|
|
* If this is a realtime file, data may be on a different device.
|
|
|
|
* to that pointed to from the buffer_head b_bdev currently.
|
|
|
|
*/
|
2010-04-28 12:28:52 +00:00
|
|
|
bh_result->b_bdev = xfs_find_bdev_for_inode(inode);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2006-03-29 00:44:40 +00:00
|
|
|
/*
|
2007-02-10 07:36:35 +00:00
|
|
|
* If we previously allocated a block out beyond eof and we are now
|
|
|
|
* coming back to use it then we will need to flag it as new even if it
|
|
|
|
* has a disk address.
|
|
|
|
*
|
|
|
|
* With sub-block writes into unwritten extents we also need to mark
|
|
|
|
* the buffer as new so that the unwritten parts of the buffer gets
|
|
|
|
* correctly zeroed.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
|
|
|
if (create &&
|
|
|
|
((!buffer_mapped(bh_result) && !buffer_uptodate(bh_result)) ||
|
2007-02-10 07:36:35 +00:00
|
|
|
(offset >= i_size_read(inode)) ||
|
2010-04-28 12:28:56 +00:00
|
|
|
(new || ISUNWRITTEN(&imap))))
|
2005-04-16 22:20:36 +00:00
|
|
|
set_buffer_new(bh_result);
|
|
|
|
|
2010-04-28 12:28:56 +00:00
|
|
|
if (imap.br_startblock == DELAYSTARTBLOCK) {
|
2005-04-16 22:20:36 +00:00
|
|
|
BUG_ON(direct);
|
|
|
|
if (create) {
|
|
|
|
set_buffer_uptodate(bh_result);
|
|
|
|
set_buffer_mapped(bh_result);
|
|
|
|
set_buffer_delay(bh_result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-28 12:28:59 +00:00
|
|
|
/*
|
|
|
|
* If this is O_DIRECT or the mpage code calling tell them how large
|
|
|
|
* the mapping is, so that we can avoid repeated get_blocks calls.
|
|
|
|
*/
|
2006-03-29 00:44:40 +00:00
|
|
|
if (direct || size > (1 << inode->i_blkbits)) {
|
2010-04-28 12:28:59 +00:00
|
|
|
xfs_off_t mapping_size;
|
|
|
|
|
|
|
|
mapping_size = imap.br_startoff + imap.br_blockcount - iblock;
|
|
|
|
mapping_size <<= inode->i_blkbits;
|
|
|
|
|
|
|
|
ASSERT(mapping_size > 0);
|
|
|
|
if (mapping_size > size)
|
|
|
|
mapping_size = size;
|
|
|
|
if (mapping_size > LONG_MAX)
|
|
|
|
mapping_size = LONG_MAX;
|
|
|
|
|
|
|
|
bh_result->b_size = mapping_size;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2006-03-29 00:44:40 +00:00
|
|
|
xfs_get_blocks(
|
2005-04-16 22:20:36 +00:00
|
|
|
struct inode *inode,
|
|
|
|
sector_t iblock,
|
|
|
|
struct buffer_head *bh_result,
|
|
|
|
int create)
|
|
|
|
{
|
2006-03-29 00:44:40 +00:00
|
|
|
return __xfs_get_blocks(inode, iblock,
|
2006-03-26 09:38:01 +00:00
|
|
|
bh_result, create, 0, BMAPI_WRITE);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
STATIC int
|
2006-03-14 02:54:26 +00:00
|
|
|
xfs_get_blocks_direct(
|
2005-04-16 22:20:36 +00:00
|
|
|
struct inode *inode,
|
|
|
|
sector_t iblock,
|
|
|
|
struct buffer_head *bh_result,
|
|
|
|
int create)
|
|
|
|
{
|
2006-03-29 00:44:40 +00:00
|
|
|
return __xfs_get_blocks(inode, iblock,
|
2006-03-26 09:38:02 +00:00
|
|
|
bh_result, create, 1, BMAPI_WRITE|BMAPI_DIRECT);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2005-09-04 22:22:52 +00:00
|
|
|
STATIC void
|
2006-03-14 02:54:26 +00:00
|
|
|
xfs_end_io_direct(
|
2005-09-04 22:22:52 +00:00
|
|
|
struct kiocb *iocb,
|
|
|
|
loff_t offset,
|
|
|
|
ssize_t size,
|
|
|
|
void *private)
|
|
|
|
{
|
|
|
|
xfs_ioend_t *ioend = iocb->private;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Non-NULL private data means we need to issue a transaction to
|
|
|
|
* convert a range from unwritten to written extents. This needs
|
2006-03-28 22:55:14 +00:00
|
|
|
* to happen from process context but aio+dio I/O completion
|
2005-09-04 22:22:52 +00:00
|
|
|
* happens from irq context so we need to defer it to a workqueue.
|
2006-03-28 22:55:14 +00:00
|
|
|
* This is not necessary for synchronous direct I/O, but we do
|
2005-09-04 22:22:52 +00:00
|
|
|
* it anyway to keep the code uniform and simpler.
|
|
|
|
*
|
2007-06-05 06:24:36 +00:00
|
|
|
* Well, if only it were that simple. Because synchronous direct I/O
|
|
|
|
* requires extent conversion to occur *before* we return to userspace,
|
|
|
|
* we have to wait for extent conversion to complete. Look at the
|
|
|
|
* iocb that has been passed to us to determine if this is AIO or
|
|
|
|
* not. If it is synchronous, tell xfs_finish_ioend() to kick the
|
|
|
|
* workqueue and wait for it to complete.
|
|
|
|
*
|
2005-09-04 22:22:52 +00:00
|
|
|
* The core direct I/O code might be changed to always call the
|
|
|
|
* completion handler in the future, in which case all this can
|
|
|
|
* go away.
|
|
|
|
*/
|
[XFS] Fix to prevent the notorious 'NULL files' problem after a crash.
The problem that has been addressed is that of synchronising updates of
the file size with writes that extend a file. Without the fix the update
of a file's size, as a result of a write beyond eof, is independent of
when the cached data is flushed to disk. Often the file size update would
be written to the filesystem log before the data is flushed to disk. When
a system crashes between these two events and the filesystem log is
replayed on mount the file's size will be set but since the contents never
made it to disk the file is full of holes. If some of the cached data was
flushed to disk then it may just be a section of the file at the end that
has holes.
There are existing fixes to help alleviate this problem, particularly in
the case where a file has been truncated, that force cached data to be
flushed to disk when the file is closed. If the system crashes while the
file(s) are still open then this flushing will never occur.
The fix that we have implemented is to introduce a second file size,
called the in-memory file size, that represents the current file size as
viewed by the user. The existing file size, called the on-disk file size,
is the one that get's written to the filesystem log and we only update it
when it is safe to do so. When we write to a file beyond eof we only
update the in- memory file size in the write operation. Later when the I/O
operation, that flushes the cached data to disk completes, an I/O
completion routine will update the on-disk file size. The on-disk file
size will be updated to the maximum offset of the I/O or to the value of
the in-memory file size if the I/O includes eof.
SGI-PV: 958522
SGI-Modid: xfs-linux-melb:xfs-kern:28322a
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
2007-05-08 03:49:46 +00:00
|
|
|
ioend->io_offset = offset;
|
|
|
|
ioend->io_size = size;
|
2010-04-28 12:28:57 +00:00
|
|
|
if (ioend->io_type == IO_READ) {
|
2007-06-05 06:24:36 +00:00
|
|
|
xfs_finish_ioend(ioend, 0);
|
[XFS] Fix to prevent the notorious 'NULL files' problem after a crash.
The problem that has been addressed is that of synchronising updates of
the file size with writes that extend a file. Without the fix the update
of a file's size, as a result of a write beyond eof, is independent of
when the cached data is flushed to disk. Often the file size update would
be written to the filesystem log before the data is flushed to disk. When
a system crashes between these two events and the filesystem log is
replayed on mount the file's size will be set but since the contents never
made it to disk the file is full of holes. If some of the cached data was
flushed to disk then it may just be a section of the file at the end that
has holes.
There are existing fixes to help alleviate this problem, particularly in
the case where a file has been truncated, that force cached data to be
flushed to disk when the file is closed. If the system crashes while the
file(s) are still open then this flushing will never occur.
The fix that we have implemented is to introduce a second file size,
called the in-memory file size, that represents the current file size as
viewed by the user. The existing file size, called the on-disk file size,
is the one that get's written to the filesystem log and we only update it
when it is safe to do so. When we write to a file beyond eof we only
update the in- memory file size in the write operation. Later when the I/O
operation, that flushes the cached data to disk completes, an I/O
completion routine will update the on-disk file size. The on-disk file
size will be updated to the maximum offset of the I/O or to the value of
the in-memory file size if the I/O includes eof.
SGI-PV: 958522
SGI-Modid: xfs-linux-melb:xfs-kern:28322a
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
2007-05-08 03:49:46 +00:00
|
|
|
} else if (private && size > 0) {
|
2007-06-05 06:24:36 +00:00
|
|
|
xfs_finish_ioend(ioend, is_sync_kiocb(iocb));
|
2005-09-04 22:22:52 +00:00
|
|
|
} else {
|
[XFS] Fix to prevent the notorious 'NULL files' problem after a crash.
The problem that has been addressed is that of synchronising updates of
the file size with writes that extend a file. Without the fix the update
of a file's size, as a result of a write beyond eof, is independent of
when the cached data is flushed to disk. Often the file size update would
be written to the filesystem log before the data is flushed to disk. When
a system crashes between these two events and the filesystem log is
replayed on mount the file's size will be set but since the contents never
made it to disk the file is full of holes. If some of the cached data was
flushed to disk then it may just be a section of the file at the end that
has holes.
There are existing fixes to help alleviate this problem, particularly in
the case where a file has been truncated, that force cached data to be
flushed to disk when the file is closed. If the system crashes while the
file(s) are still open then this flushing will never occur.
The fix that we have implemented is to introduce a second file size,
called the in-memory file size, that represents the current file size as
viewed by the user. The existing file size, called the on-disk file size,
is the one that get's written to the filesystem log and we only update it
when it is safe to do so. When we write to a file beyond eof we only
update the in- memory file size in the write operation. Later when the I/O
operation, that flushes the cached data to disk completes, an I/O
completion routine will update the on-disk file size. The on-disk file
size will be updated to the maximum offset of the I/O or to the value of
the in-memory file size if the I/O includes eof.
SGI-PV: 958522
SGI-Modid: xfs-linux-melb:xfs-kern:28322a
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
2007-05-08 03:49:46 +00:00
|
|
|
/*
|
|
|
|
* A direct I/O write ioend starts it's life in unwritten
|
|
|
|
* state in case they map an unwritten extent. This write
|
|
|
|
* didn't map an unwritten extent so switch it's completion
|
|
|
|
* handler.
|
|
|
|
*/
|
2010-04-28 12:28:57 +00:00
|
|
|
ioend->io_type = IO_NEW;
|
2007-06-05 06:24:36 +00:00
|
|
|
xfs_finish_ioend(ioend, 0);
|
2005-09-04 22:22:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-03-28 22:55:14 +00:00
|
|
|
* blockdev_direct_IO can return an error even after the I/O
|
2005-09-04 22:22:52 +00:00
|
|
|
* completion handler was called. Thus we need to protect
|
|
|
|
* against double-freeing.
|
|
|
|
*/
|
|
|
|
iocb->private = NULL;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
STATIC ssize_t
|
2006-03-14 02:54:26 +00:00
|
|
|
xfs_vm_direct_IO(
|
2005-04-16 22:20:36 +00:00
|
|
|
int rw,
|
|
|
|
struct kiocb *iocb,
|
|
|
|
const struct iovec *iov,
|
|
|
|
loff_t offset,
|
|
|
|
unsigned long nr_segs)
|
|
|
|
{
|
|
|
|
struct file *file = iocb->ki_filp;
|
|
|
|
struct inode *inode = file->f_mapping->host;
|
2007-09-14 05:23:17 +00:00
|
|
|
struct block_device *bdev;
|
2005-09-04 22:22:52 +00:00
|
|
|
ssize_t ret;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2010-04-28 12:28:52 +00:00
|
|
|
bdev = xfs_find_bdev_for_inode(inode);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
direct-io: cleanup blockdev_direct_IO locking
Currently the locking in blockdev_direct_IO is a mess, we have three
different locking types and very confusing checks for some of them. The
most complicated one is DIO_OWN_LOCKING for reads, which happens to not
actually be used.
This patch gets rid of the DIO_OWN_LOCKING - as mentioned above the read
case is unused anyway, and the write side is almost identical to
DIO_NO_LOCKING. The difference is that DIO_NO_LOCKING always sets the
create argument for the get_blocks callback to zero, but we can easily
move that to the actual get_blocks callbacks. There are four users of the
DIO_NO_LOCKING mode: gfs already ignores the create argument and thus is
fine with the new version, ocfs2 only errors out if create were ever set,
and we can remove this dead code now, the block device code only ever uses
create for an error message if we are fully beyond the device which can
never happen, and last but not least XFS will need the new behavour for
writes.
Now we can replace the lock_type variable with a flags one, where no flag
means the DIO_NO_LOCKING behaviour and DIO_LOCKING is kept as the first
flag. Separate out the check for not allowing to fill holes into a
separate flag, although for now both flags always get set at the same
time.
Also revamp the documentation of the locking scheme to actually make
sense.
[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Christoph Hellwig <hch@lst.de>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Badari Pulavarty <pbadari@us.ibm.com>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Jens Axboe <jens.axboe@oracle.com>
Cc: Zach Brown <zach.brown@oracle.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Alex Elder <aelder@sgi.com>
Cc: Mark Fasheh <mfasheh@suse.com>
Cc: Joel Becker <joel.becker@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-12-16 00:47:50 +00:00
|
|
|
iocb->private = xfs_alloc_ioend(inode, rw == WRITE ?
|
2010-04-28 12:28:57 +00:00
|
|
|
IO_UNWRITTEN : IO_READ);
|
direct-io: cleanup blockdev_direct_IO locking
Currently the locking in blockdev_direct_IO is a mess, we have three
different locking types and very confusing checks for some of them. The
most complicated one is DIO_OWN_LOCKING for reads, which happens to not
actually be used.
This patch gets rid of the DIO_OWN_LOCKING - as mentioned above the read
case is unused anyway, and the write side is almost identical to
DIO_NO_LOCKING. The difference is that DIO_NO_LOCKING always sets the
create argument for the get_blocks callback to zero, but we can easily
move that to the actual get_blocks callbacks. There are four users of the
DIO_NO_LOCKING mode: gfs already ignores the create argument and thus is
fine with the new version, ocfs2 only errors out if create were ever set,
and we can remove this dead code now, the block device code only ever uses
create for an error message if we are fully beyond the device which can
never happen, and last but not least XFS will need the new behavour for
writes.
Now we can replace the lock_type variable with a flags one, where no flag
means the DIO_NO_LOCKING behaviour and DIO_LOCKING is kept as the first
flag. Separate out the check for not allowing to fill holes into a
separate flag, although for now both flags always get set at the same
time.
Also revamp the documentation of the locking scheme to actually make
sense.
[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Christoph Hellwig <hch@lst.de>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Badari Pulavarty <pbadari@us.ibm.com>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Jens Axboe <jens.axboe@oracle.com>
Cc: Zach Brown <zach.brown@oracle.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Alex Elder <aelder@sgi.com>
Cc: Mark Fasheh <mfasheh@suse.com>
Cc: Joel Becker <joel.becker@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-12-16 00:47:50 +00:00
|
|
|
|
|
|
|
ret = blockdev_direct_IO_no_locking(rw, iocb, inode, bdev, iov,
|
|
|
|
offset, nr_segs,
|
|
|
|
xfs_get_blocks_direct,
|
|
|
|
xfs_end_io_direct);
|
2005-09-04 22:22:52 +00:00
|
|
|
|
2006-12-10 10:21:05 +00:00
|
|
|
if (unlikely(ret != -EIOCBQUEUED && iocb->private))
|
2005-09-04 22:22:52 +00:00
|
|
|
xfs_destroy_ioend(iocb->private);
|
|
|
|
return ret;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2006-03-14 02:26:27 +00:00
|
|
|
STATIC int
|
2007-10-16 08:25:06 +00:00
|
|
|
xfs_vm_write_begin(
|
2006-03-14 02:26:27 +00:00
|
|
|
struct file *file,
|
2007-10-16 08:25:06 +00:00
|
|
|
struct address_space *mapping,
|
|
|
|
loff_t pos,
|
|
|
|
unsigned len,
|
|
|
|
unsigned flags,
|
|
|
|
struct page **pagep,
|
|
|
|
void **fsdata)
|
2006-03-14 02:26:27 +00:00
|
|
|
{
|
2007-10-16 08:25:06 +00:00
|
|
|
*pagep = NULL;
|
|
|
|
return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
|
|
|
|
xfs_get_blocks);
|
2006-03-14 02:26:27 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
STATIC sector_t
|
2006-03-14 02:54:26 +00:00
|
|
|
xfs_vm_bmap(
|
2005-04-16 22:20:36 +00:00
|
|
|
struct address_space *mapping,
|
|
|
|
sector_t block)
|
|
|
|
{
|
|
|
|
struct inode *inode = (struct inode *)mapping->host;
|
2007-08-29 00:58:01 +00:00
|
|
|
struct xfs_inode *ip = XFS_I(inode);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2008-02-07 05:42:19 +00:00
|
|
|
xfs_itrace_entry(XFS_I(inode));
|
2008-03-06 02:44:57 +00:00
|
|
|
xfs_ilock(ip, XFS_IOLOCK_SHARED);
|
2007-08-29 00:58:01 +00:00
|
|
|
xfs_flush_pages(ip, (xfs_off_t)0, -1, 0, FI_REMAPF);
|
2008-03-06 02:44:57 +00:00
|
|
|
xfs_iunlock(ip, XFS_IOLOCK_SHARED);
|
2006-03-29 00:44:40 +00:00
|
|
|
return generic_block_bmap(mapping, block, xfs_get_blocks);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
STATIC int
|
2006-03-14 02:54:26 +00:00
|
|
|
xfs_vm_readpage(
|
2005-04-16 22:20:36 +00:00
|
|
|
struct file *unused,
|
|
|
|
struct page *page)
|
|
|
|
{
|
2006-03-29 00:44:40 +00:00
|
|
|
return mpage_readpage(page, xfs_get_blocks);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
STATIC int
|
2006-03-14 02:54:26 +00:00
|
|
|
xfs_vm_readpages(
|
2005-04-16 22:20:36 +00:00
|
|
|
struct file *unused,
|
|
|
|
struct address_space *mapping,
|
|
|
|
struct list_head *pages,
|
|
|
|
unsigned nr_pages)
|
|
|
|
{
|
2006-03-29 00:44:40 +00:00
|
|
|
return mpage_readpages(mapping, pages, nr_pages, xfs_get_blocks);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2006-06-28 11:26:44 +00:00
|
|
|
const struct address_space_operations xfs_address_space_operations = {
|
2006-03-14 02:54:26 +00:00
|
|
|
.readpage = xfs_vm_readpage,
|
|
|
|
.readpages = xfs_vm_readpages,
|
|
|
|
.writepage = xfs_vm_writepage,
|
2006-06-09 05:27:16 +00:00
|
|
|
.writepages = xfs_vm_writepages,
|
2005-04-16 22:20:36 +00:00
|
|
|
.sync_page = block_sync_page,
|
2006-03-17 06:26:25 +00:00
|
|
|
.releasepage = xfs_vm_releasepage,
|
|
|
|
.invalidatepage = xfs_vm_invalidatepage,
|
2007-10-16 08:25:06 +00:00
|
|
|
.write_begin = xfs_vm_write_begin,
|
|
|
|
.write_end = generic_write_end,
|
2006-03-14 02:54:26 +00:00
|
|
|
.bmap = xfs_vm_bmap,
|
|
|
|
.direct_IO = xfs_vm_direct_IO,
|
2006-02-01 11:05:41 +00:00
|
|
|
.migratepage = buffer_migrate_page,
|
2009-03-29 07:53:38 +00:00
|
|
|
.is_partially_uptodate = block_is_partially_uptodate,
|
2009-09-16 09:50:16 +00:00
|
|
|
.error_remove_page = generic_error_remove_page,
|
2005-04-16 22:20:36 +00:00
|
|
|
};
|