2005-04-17 00:20:36 +02:00
|
|
|
/*
|
2005-11-02 04:58:39 +01:00
|
|
|
* Copyright (c) 2000-2005 Silicon Graphics, Inc.
|
|
|
|
* All Rights Reserved.
|
2005-04-17 00:20:36 +02:00
|
|
|
*
|
2005-11-02 04:58:39 +01: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-17 00:20:36 +02:00
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
2005-11-02 04:58:39 +01: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-17 00:20:36 +02:00
|
|
|
*
|
2005-11-02 04:58:39 +01: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-17 00:20:36 +02:00
|
|
|
*/
|
|
|
|
#include "xfs.h"
|
2005-11-02 04:38:42 +01:00
|
|
|
#include "xfs_bit.h"
|
2005-04-17 00:20:36 +02:00
|
|
|
#include "xfs_log.h"
|
2005-11-02 04:38:42 +01:00
|
|
|
#include "xfs_inum.h"
|
2005-04-17 00:20:36 +02:00
|
|
|
#include "xfs_sb.h"
|
2005-11-02 04:38:42 +01:00
|
|
|
#include "xfs_ag.h"
|
2005-04-17 00:20:36 +02:00
|
|
|
#include "xfs_trans.h"
|
|
|
|
#include "xfs_mount.h"
|
|
|
|
#include "xfs_bmap_btree.h"
|
|
|
|
#include "xfs_dinode.h"
|
|
|
|
#include "xfs_inode.h"
|
2012-03-13 09:41:05 +01:00
|
|
|
#include "xfs_inode_item.h"
|
2005-11-02 04:38:42 +01:00
|
|
|
#include "xfs_alloc.h"
|
2005-04-17 00:20:36 +02:00
|
|
|
#include "xfs_error.h"
|
|
|
|
#include "xfs_rw.h"
|
|
|
|
#include "xfs_iomap.h"
|
2007-08-29 02:58:01 +02:00
|
|
|
#include "xfs_vnodeops.h"
|
2009-12-15 00:14:59 +01:00
|
|
|
#include "xfs_trace.h"
|
2010-03-05 03:00:42 +01: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 09:04:11 +01:00
|
|
|
#include <linux/gfp.h>
|
2005-04-17 00:20:36 +02:00
|
|
|
#include <linux/mpage.h>
|
2006-01-11 10:48:14 +01:00
|
|
|
#include <linux/pagevec.h>
|
2005-04-17 00:20:36 +02:00
|
|
|
#include <linux/writeback.h>
|
|
|
|
|
2009-12-15 00:14:59 +01:00
|
|
|
void
|
2006-03-14 03:26:27 +01:00
|
|
|
xfs_count_page_state(
|
|
|
|
struct page *page,
|
|
|
|
int *delalloc,
|
|
|
|
int *unwritten)
|
|
|
|
{
|
|
|
|
struct buffer_head *bh, *head;
|
|
|
|
|
2010-06-24 01:46:01 +02:00
|
|
|
*delalloc = *unwritten = 0;
|
2006-03-14 03:26:27 +01:00
|
|
|
|
|
|
|
bh = head = page_buffers(page);
|
|
|
|
do {
|
2010-06-24 01:46:01 +02:00
|
|
|
if (buffer_unwritten(bh))
|
2006-03-14 03:26:27 +01:00
|
|
|
(*unwritten) = 1;
|
|
|
|
else if (buffer_delay(bh))
|
|
|
|
(*delalloc) = 1;
|
|
|
|
} while ((bh = bh->b_this_page) != head);
|
|
|
|
}
|
|
|
|
|
2007-09-14 07:23:17 +02:00
|
|
|
STATIC struct block_device *
|
|
|
|
xfs_find_bdev_for_inode(
|
2010-04-28 14:28:52 +02:00
|
|
|
struct inode *inode)
|
2007-09-14 07:23:17 +02:00
|
|
|
{
|
2010-04-28 14:28:52 +02:00
|
|
|
struct xfs_inode *ip = XFS_I(inode);
|
2007-09-14 07:23:17 +02:00
|
|
|
struct xfs_mount *mp = ip->i_mount;
|
|
|
|
|
2007-11-23 06:29:42 +01:00
|
|
|
if (XFS_IS_REALTIME_INODE(ip))
|
2007-09-14 07:23:17 +02:00
|
|
|
return mp->m_rtdev_targp->bt_bdev;
|
|
|
|
else
|
|
|
|
return mp->m_ddev_targp->bt_bdev;
|
|
|
|
}
|
|
|
|
|
2006-01-11 05:40:13 +01: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 08:58:49 +02:00
|
|
|
STATIC void
|
|
|
|
xfs_destroy_ioend(
|
|
|
|
xfs_ioend_t *ioend)
|
|
|
|
{
|
2006-01-11 05:40:13 +01:00
|
|
|
struct buffer_head *bh, *next;
|
|
|
|
|
|
|
|
for (bh = ioend->io_buffer_head; bh; bh = next) {
|
|
|
|
next = bh->b_private;
|
2006-06-09 06:58:38 +02:00
|
|
|
bh->b_end_io(bh, !ioend->io_error);
|
2006-01-11 05:40:13 +01:00
|
|
|
}
|
2008-12-03 12:20:38 +01:00
|
|
|
|
2011-08-23 10:28:10 +02:00
|
|
|
if (ioend->io_iocb) {
|
2011-08-24 07:59:25 +02:00
|
|
|
if (ioend->io_isasync) {
|
|
|
|
aio_complete(ioend->io_iocb, ioend->io_error ?
|
|
|
|
ioend->io_error : ioend->io_result, 0);
|
|
|
|
}
|
2011-08-23 10:28:10 +02:00
|
|
|
inode_dio_done(ioend->io_inode);
|
|
|
|
}
|
2011-08-23 10:28:13 +02:00
|
|
|
|
2005-09-02 08:58:49 +02:00
|
|
|
mempool_free(ioend, xfs_ioend_pool);
|
|
|
|
}
|
|
|
|
|
2011-08-23 10:28:11 +02:00
|
|
|
/*
|
|
|
|
* Fast and loose check if this write could update the on-disk inode size.
|
|
|
|
*/
|
|
|
|
static inline bool xfs_ioend_is_append(struct xfs_ioend *ioend)
|
|
|
|
{
|
|
|
|
return ioend->io_offset + ioend->io_size >
|
|
|
|
XFS_I(ioend->io_inode)->i_d.di_size;
|
|
|
|
}
|
|
|
|
|
2012-03-13 09:41:05 +01:00
|
|
|
STATIC int
|
|
|
|
xfs_setfilesize_trans_alloc(
|
|
|
|
struct xfs_ioend *ioend)
|
|
|
|
{
|
|
|
|
struct xfs_mount *mp = XFS_I(ioend->io_inode)->i_mount;
|
|
|
|
struct xfs_trans *tp;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
|
|
|
|
|
|
|
|
error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
|
|
|
|
if (error) {
|
|
|
|
xfs_trans_cancel(tp, 0);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ioend->io_append_trans = tp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We hand off the transaction to the completion thread now, so
|
|
|
|
* clear the flag here.
|
|
|
|
*/
|
|
|
|
current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
|
|
|
|
return 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 05:49:46 +02:00
|
|
|
/*
|
2011-12-18 21:00:12 +01:00
|
|
|
* Update on-disk file size now that data has been written to disk.
|
[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 05:49:46 +02:00
|
|
|
*/
|
2012-03-13 09:41:05 +01: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 05:49:46 +02:00
|
|
|
xfs_setfilesize(
|
2012-02-29 10:53:48 +01:00
|
|
|
struct xfs_ioend *ioend)
|
[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 05:49:46 +02:00
|
|
|
{
|
2012-02-29 10:53:48 +01:00
|
|
|
struct xfs_inode *ip = XFS_I(ioend->io_inode);
|
2012-03-13 09:41:05 +01:00
|
|
|
struct xfs_trans *tp = ioend->io_append_trans;
|
[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 05:49:46 +02:00
|
|
|
xfs_fsize_t isize;
|
|
|
|
|
2012-03-13 09:41:05 +01:00
|
|
|
/*
|
|
|
|
* The transaction was allocated in the I/O submission thread,
|
|
|
|
* thus we need to mark ourselves as beeing in a transaction
|
|
|
|
* manually.
|
|
|
|
*/
|
|
|
|
current_set_flags_nested(&tp->t_pflags, PF_FSTRANS);
|
|
|
|
|
2012-02-29 10:53:48 +01:00
|
|
|
xfs_ilock(ip, XFS_ILOCK_EXCL);
|
2012-02-29 10:53:49 +01:00
|
|
|
isize = xfs_new_eof(ip, ioend->io_offset + ioend->io_size);
|
2012-03-13 09:41:05 +01:00
|
|
|
if (!isize) {
|
|
|
|
xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
|
|
|
xfs_trans_cancel(tp, 0);
|
|
|
|
return 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 05:49:46 +02:00
|
|
|
}
|
|
|
|
|
2012-03-13 09:41:05 +01:00
|
|
|
trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size);
|
|
|
|
|
|
|
|
ip->i_d.di_size = isize;
|
|
|
|
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
|
|
|
|
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
|
|
|
|
|
|
|
|
return xfs_trans_commit(tp, 0);
|
2010-02-17 06:36:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2010-07-18 23:17:11 +02:00
|
|
|
* Schedule IO completion handling on the final put of an ioend.
|
2011-08-23 10:28:11 +02:00
|
|
|
*
|
|
|
|
* If there is no work to do we might as well call it a day and free the
|
|
|
|
* ioend right now.
|
2010-02-17 06:36:29 +01:00
|
|
|
*/
|
|
|
|
STATIC void
|
|
|
|
xfs_finish_ioend(
|
2010-07-18 23:17:11 +02:00
|
|
|
struct xfs_ioend *ioend)
|
2010-02-17 06:36:29 +01:00
|
|
|
{
|
|
|
|
if (atomic_dec_and_test(&ioend->io_remaining)) {
|
2012-02-29 10:53:48 +01:00
|
|
|
struct xfs_mount *mp = XFS_I(ioend->io_inode)->i_mount;
|
|
|
|
|
2010-07-18 23:17:11 +02:00
|
|
|
if (ioend->io_type == IO_UNWRITTEN)
|
2012-02-29 10:53:48 +01:00
|
|
|
queue_work(mp->m_unwritten_workqueue, &ioend->io_work);
|
2012-03-13 09:41:05 +01:00
|
|
|
else if (ioend->io_append_trans)
|
2012-02-29 10:53:48 +01:00
|
|
|
queue_work(mp->m_data_workqueue, &ioend->io_work);
|
2011-08-23 10:28:11 +02:00
|
|
|
else
|
|
|
|
xfs_destroy_ioend(ioend);
|
2010-02-17 06:36:29 +01:00
|
|
|
}
|
[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 05:49:46 +02:00
|
|
|
}
|
|
|
|
|
2005-09-02 08:58:49 +02:00
|
|
|
/*
|
2009-10-30 10:11:47 +01:00
|
|
|
* IO write completion.
|
2006-01-11 05:40:13 +01:00
|
|
|
*/
|
|
|
|
STATIC void
|
2009-10-30 10:11:47 +01:00
|
|
|
xfs_end_io(
|
2010-02-17 06:36:29 +01:00
|
|
|
struct work_struct *work)
|
2005-09-02 08:58:49 +02:00
|
|
|
{
|
2010-02-17 06:36:29 +01: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 01:57:09 +01: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 05:49:46 +02:00
|
|
|
|
2011-08-24 07:59:25 +02:00
|
|
|
if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
|
2011-11-08 09:56:15 +01:00
|
|
|
ioend->io_error = -EIO;
|
2011-08-24 07:59:25 +02:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
if (ioend->io_error)
|
|
|
|
goto done;
|
|
|
|
|
2009-10-30 10:11:47 +01:00
|
|
|
/*
|
|
|
|
* For unwritten extents we need to issue transactions to convert a
|
|
|
|
* range to normal written extens after the data I/O has finished.
|
|
|
|
*/
|
2011-08-24 07:59:25 +02:00
|
|
|
if (ioend->io_type == IO_UNWRITTEN) {
|
2012-03-13 09:41:05 +01:00
|
|
|
/*
|
|
|
|
* For buffered I/O we never preallocate a transaction when
|
|
|
|
* doing the unwritten extent conversion, but for direct I/O
|
|
|
|
* we do not know if we are converting an unwritten extent
|
|
|
|
* or not at the point where we preallocate the transaction.
|
|
|
|
*/
|
|
|
|
if (ioend->io_append_trans) {
|
|
|
|
ASSERT(ioend->io_isdirect);
|
|
|
|
|
|
|
|
current_set_flags_nested(
|
|
|
|
&ioend->io_append_trans->t_pflags, PF_FSTRANS);
|
|
|
|
xfs_trans_cancel(ioend->io_append_trans, 0);
|
|
|
|
}
|
|
|
|
|
2009-10-30 10:11:47 +01:00
|
|
|
error = xfs_iomap_write_unwritten(ip, ioend->io_offset,
|
|
|
|
ioend->io_size);
|
2011-08-24 07:59:25 +02:00
|
|
|
if (error) {
|
|
|
|
ioend->io_error = -error;
|
|
|
|
goto done;
|
|
|
|
}
|
2012-03-13 09:41:05 +01:00
|
|
|
} else if (ioend->io_append_trans) {
|
|
|
|
error = xfs_setfilesize(ioend);
|
|
|
|
if (error)
|
|
|
|
ioend->io_error = -error;
|
2012-02-29 10:53:50 +01:00
|
|
|
} else {
|
2012-03-13 09:41:05 +01:00
|
|
|
ASSERT(!xfs_ioend_is_append(ioend));
|
2009-10-30 10:11:47 +01:00
|
|
|
}
|
[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 05:49:46 +02:00
|
|
|
|
2011-08-24 07:59:25 +02:00
|
|
|
done:
|
2012-02-29 10:53:48 +01:00
|
|
|
xfs_destroy_ioend(ioend);
|
2009-04-06 18:42:11 +02:00
|
|
|
}
|
|
|
|
|
2010-07-18 23:17:11 +02:00
|
|
|
/*
|
|
|
|
* Call IO completion handling in caller context on the final put of an ioend.
|
|
|
|
*/
|
|
|
|
STATIC void
|
|
|
|
xfs_finish_ioend_sync(
|
|
|
|
struct xfs_ioend *ioend)
|
|
|
|
{
|
|
|
|
if (atomic_dec_and_test(&ioend->io_remaining))
|
|
|
|
xfs_end_io(&ioend->io_work);
|
|
|
|
}
|
|
|
|
|
2005-09-02 08:58:49 +02: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 05:40:13 +01:00
|
|
|
struct inode *inode,
|
|
|
|
unsigned int type)
|
2005-09-02 08:58:49 +02: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);
|
2011-08-23 10:28:10 +02:00
|
|
|
ioend->io_isasync = 0;
|
2012-03-13 09:41:05 +01:00
|
|
|
ioend->io_isdirect = 0;
|
2006-06-09 06:58:38 +02:00
|
|
|
ioend->io_error = 0;
|
2006-01-11 05:40:13 +01:00
|
|
|
ioend->io_list = NULL;
|
|
|
|
ioend->io_type = type;
|
2007-08-29 03:46:28 +02:00
|
|
|
ioend->io_inode = inode;
|
2005-09-05 00:23:35 +02:00
|
|
|
ioend->io_buffer_head = NULL;
|
2006-01-11 05:40:13 +01:00
|
|
|
ioend->io_buffer_tail = NULL;
|
2005-09-02 08:58:49 +02:00
|
|
|
ioend->io_offset = 0;
|
|
|
|
ioend->io_size = 0;
|
2010-07-18 23:17:10 +02:00
|
|
|
ioend->io_iocb = NULL;
|
|
|
|
ioend->io_result = 0;
|
2012-03-13 09:41:05 +01:00
|
|
|
ioend->io_append_trans = NULL;
|
2005-09-02 08:58:49 +02:00
|
|
|
|
2009-10-30 10:11:47 +01:00
|
|
|
INIT_WORK(&ioend->io_work, xfs_end_io);
|
2005-09-02 08:58:49 +02:00
|
|
|
return ioend;
|
|
|
|
}
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
STATIC int
|
|
|
|
xfs_map_blocks(
|
|
|
|
struct inode *inode,
|
|
|
|
loff_t offset,
|
2010-04-28 14:28:56 +02:00
|
|
|
struct xfs_bmbt_irec *imap,
|
2010-12-10 09:42:20 +01:00
|
|
|
int type,
|
|
|
|
int nonblocking)
|
2005-04-17 00:20:36 +02:00
|
|
|
{
|
2010-12-10 09:42:20 +01:00
|
|
|
struct xfs_inode *ip = XFS_I(inode);
|
|
|
|
struct xfs_mount *mp = ip->i_mount;
|
2010-12-10 09:42:22 +01:00
|
|
|
ssize_t count = 1 << inode->i_blkbits;
|
2010-12-10 09:42:20 +01:00
|
|
|
xfs_fileoff_t offset_fsb, end_fsb;
|
|
|
|
int error = 0;
|
|
|
|
int bmapi_flags = XFS_BMAPI_ENTIRE;
|
|
|
|
int nimaps = 1;
|
|
|
|
|
|
|
|
if (XFS_FORCED_SHUTDOWN(mp))
|
|
|
|
return -XFS_ERROR(EIO);
|
|
|
|
|
2010-12-10 09:42:21 +01:00
|
|
|
if (type == IO_UNWRITTEN)
|
2010-12-10 09:42:20 +01:00
|
|
|
bmapi_flags |= XFS_BMAPI_IGSTATE;
|
2010-12-10 09:42:21 +01:00
|
|
|
|
|
|
|
if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) {
|
|
|
|
if (nonblocking)
|
|
|
|
return -XFS_ERROR(EAGAIN);
|
|
|
|
xfs_ilock(ip, XFS_ILOCK_SHARED);
|
2010-12-10 09:42:20 +01:00
|
|
|
}
|
|
|
|
|
2010-12-10 09:42:21 +01:00
|
|
|
ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
|
|
|
|
(ip->i_df.if_flags & XFS_IFEXTENTS));
|
2010-12-10 09:42:20 +01:00
|
|
|
ASSERT(offset <= mp->m_maxioffset);
|
2010-12-10 09:42:21 +01:00
|
|
|
|
2010-12-10 09:42:20 +01:00
|
|
|
if (offset + count > mp->m_maxioffset)
|
|
|
|
count = mp->m_maxioffset - offset;
|
|
|
|
end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count);
|
|
|
|
offset_fsb = XFS_B_TO_FSBT(mp, offset);
|
2011-09-18 22:40:45 +02:00
|
|
|
error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb,
|
|
|
|
imap, &nimaps, bmapi_flags);
|
2010-12-10 09:42:21 +01:00
|
|
|
xfs_iunlock(ip, XFS_ILOCK_SHARED);
|
2010-12-10 09:42:20 +01:00
|
|
|
|
2010-12-10 09:42:21 +01:00
|
|
|
if (error)
|
|
|
|
return -XFS_ERROR(error);
|
2010-12-10 09:42:20 +01:00
|
|
|
|
2010-12-10 09:42:21 +01:00
|
|
|
if (type == IO_DELALLOC &&
|
|
|
|
(!nimaps || isnullstartblock(imap->br_startblock))) {
|
2010-12-10 09:42:20 +01:00
|
|
|
error = xfs_iomap_write_allocate(ip, offset, count, imap);
|
|
|
|
if (!error)
|
|
|
|
trace_xfs_map_blocks_alloc(ip, offset, count, type, imap);
|
2010-12-10 09:42:21 +01:00
|
|
|
return -XFS_ERROR(error);
|
2010-12-10 09:42:20 +01:00
|
|
|
}
|
|
|
|
|
2010-12-10 09:42:21 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (type == IO_UNWRITTEN) {
|
|
|
|
ASSERT(nimaps);
|
|
|
|
ASSERT(imap->br_startblock != HOLESTARTBLOCK);
|
|
|
|
ASSERT(imap->br_startblock != DELAYSTARTBLOCK);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (nimaps)
|
|
|
|
trace_xfs_map_blocks_found(ip, offset, count, type, imap);
|
|
|
|
return 0;
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
|
2009-11-14 17:17:22 +01:00
|
|
|
STATIC int
|
2010-04-28 14:28:58 +02:00
|
|
|
xfs_imap_valid(
|
2010-04-28 14:28:54 +02:00
|
|
|
struct inode *inode,
|
2010-04-28 14:28:56 +02:00
|
|
|
struct xfs_bmbt_irec *imap,
|
2010-04-28 14:28:58 +02:00
|
|
|
xfs_off_t offset)
|
2005-04-17 00:20:36 +02:00
|
|
|
{
|
2010-04-28 14:28:58 +02:00
|
|
|
offset >>= inode->i_blkbits;
|
2010-04-28 14:28:54 +02:00
|
|
|
|
2010-04-28 14:28:58 +02:00
|
|
|
return offset >= imap->br_startoff &&
|
|
|
|
offset < imap->br_startoff + imap->br_blockcount;
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
|
2006-01-11 05:40:13 +01:00
|
|
|
/*
|
|
|
|
* BIO completion handler for buffered IO.
|
|
|
|
*/
|
2007-10-12 08:17:47 +02:00
|
|
|
STATIC void
|
2006-01-11 05:40:13 +01: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 06:58:38 +02:00
|
|
|
ioend->io_error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : error;
|
2006-01-11 05:40:13 +01: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 06:58:38 +02:00
|
|
|
|
2010-07-18 23:17:11 +02:00
|
|
|
xfs_finish_ioend(ioend);
|
2006-01-11 05:40:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
STATIC void
|
|
|
|
xfs_submit_ioend_bio(
|
2009-10-30 10:09:15 +01:00
|
|
|
struct writeback_control *wbc,
|
|
|
|
xfs_ioend_t *ioend,
|
|
|
|
struct bio *bio)
|
2006-01-11 05:40:13 +01:00
|
|
|
{
|
|
|
|
atomic_inc(&ioend->io_remaining);
|
|
|
|
bio->bi_private = ioend;
|
|
|
|
bio->bi_end_io = xfs_end_bio;
|
2011-03-09 11:56:30 +01:00
|
|
|
submit_bio(wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE, bio);
|
2006-01-11 05:40:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
STATIC struct bio *
|
|
|
|
xfs_alloc_ioend_bio(
|
|
|
|
struct buffer_head *bh)
|
|
|
|
{
|
|
|
|
int nvecs = bio_get_nr_vecs(bh->b_bdev);
|
2010-12-10 09:42:17 +01:00
|
|
|
struct bio *bio = bio_alloc(GFP_NOIO, nvecs);
|
2006-01-11 05:40:13 +01:00
|
|
|
|
|
|
|
ASSERT(bio->bi_private == NULL);
|
|
|
|
bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);
|
|
|
|
bio->bi_bdev = bh->b_bdev;
|
|
|
|
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-21 00:24:01 +01:00
|
|
|
clear_page_dirty_for_io(page);
|
|
|
|
set_page_writeback(page);
|
2006-01-11 05:40:13 +01:00
|
|
|
unlock_page(page);
|
2007-10-17 08:30:42 +02:00
|
|
|
/* If no buffers on the page are to be written, finish it here */
|
|
|
|
if (!buffers)
|
2006-01-11 05:40:13 +01: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 03:38:12 +01: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-29 00:55:14 +02:00
|
|
|
* buffer_heads, and then submit them for I/O on the second pass.
|
2006-01-11 05:40:13 +01:00
|
|
|
*/
|
|
|
|
STATIC void
|
|
|
|
xfs_submit_ioend(
|
2009-10-30 10:09:15 +01:00
|
|
|
struct writeback_control *wbc,
|
2006-01-11 05:40:13 +01:00
|
|
|
xfs_ioend_t *ioend)
|
|
|
|
{
|
2006-01-18 03:38:12 +01:00
|
|
|
xfs_ioend_t *head = ioend;
|
2006-01-11 05:40:13 +01:00
|
|
|
xfs_ioend_t *next;
|
|
|
|
struct buffer_head *bh;
|
|
|
|
struct bio *bio;
|
|
|
|
sector_t lastblock = 0;
|
|
|
|
|
2006-01-18 03:38:12 +01:00
|
|
|
/* Pass 1 - start writeback */
|
|
|
|
do {
|
|
|
|
next = ioend->io_list;
|
2010-12-10 09:42:17 +01:00
|
|
|
for (bh = ioend->io_buffer_head; bh; bh = bh->b_private)
|
2006-01-18 03:38:12 +01:00
|
|
|
xfs_start_buffer_writeback(bh);
|
|
|
|
} while ((ioend = next) != NULL);
|
|
|
|
|
|
|
|
/* Pass 2 - submit I/O */
|
|
|
|
ioend = head;
|
2006-01-11 05:40:13 +01: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 10:09:15 +01:00
|
|
|
xfs_submit_ioend_bio(wbc, ioend, bio);
|
2006-01-11 05:40:13 +01:00
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bio_add_buffer(bio, bh) != bh->b_size) {
|
2009-10-30 10:09:15 +01:00
|
|
|
xfs_submit_ioend_bio(wbc, ioend, bio);
|
2006-01-11 05:40:13 +01:00
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
|
|
|
lastblock = bh->b_blocknr;
|
|
|
|
}
|
|
|
|
if (bio)
|
2009-10-30 10:09:15 +01:00
|
|
|
xfs_submit_ioend_bio(wbc, ioend, bio);
|
2010-07-18 23:17:11 +02:00
|
|
|
xfs_finish_ioend(ioend);
|
2006-01-11 05:40:13 +01: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);
|
|
|
|
|
|
|
|
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 10:49:16 +01:00
|
|
|
xfs_off_t offset,
|
2006-01-11 05:40:13 +01: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 03:26:43 +01:00
|
|
|
STATIC void
|
|
|
|
xfs_map_buffer(
|
2010-04-28 14:28:52 +02:00
|
|
|
struct inode *inode,
|
2006-03-14 03:26:43 +01:00
|
|
|
struct buffer_head *bh,
|
2010-04-28 14:28:56 +02:00
|
|
|
struct xfs_bmbt_irec *imap,
|
2010-04-28 14:28:52 +02:00
|
|
|
xfs_off_t offset)
|
2006-03-14 03:26:43 +01:00
|
|
|
{
|
|
|
|
sector_t bn;
|
2010-04-28 14:28:54 +02:00
|
|
|
struct xfs_mount *m = XFS_I(inode)->i_mount;
|
2010-04-28 14:28:56 +02: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 03:26:43 +01:00
|
|
|
|
2010-04-28 14:28:56 +02:00
|
|
|
ASSERT(imap->br_startblock != HOLESTARTBLOCK);
|
|
|
|
ASSERT(imap->br_startblock != DELAYSTARTBLOCK);
|
2006-03-14 03:26:43 +01:00
|
|
|
|
2010-04-28 14:28:55 +02:00
|
|
|
bn = (iomap_bn >> (inode->i_blkbits - BBSHIFT)) +
|
2010-04-28 14:28:54 +02:00
|
|
|
((offset - iomap_offset) >> inode->i_blkbits);
|
2006-03-14 03:26:43 +01:00
|
|
|
|
2010-04-28 14:28:52 +02:00
|
|
|
ASSERT(bn || XFS_IS_REALTIME_INODE(XFS_I(inode)));
|
2006-03-14 03:26:43 +01:00
|
|
|
|
|
|
|
bh->b_blocknr = bn;
|
|
|
|
set_buffer_mapped(bh);
|
|
|
|
}
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
STATIC void
|
|
|
|
xfs_map_at_offset(
|
2010-04-28 14:28:52 +02:00
|
|
|
struct inode *inode,
|
2005-04-17 00:20:36 +02:00
|
|
|
struct buffer_head *bh,
|
2010-04-28 14:28:56 +02:00
|
|
|
struct xfs_bmbt_irec *imap,
|
2010-04-28 14:28:52 +02:00
|
|
|
xfs_off_t offset)
|
2005-04-17 00:20:36 +02:00
|
|
|
{
|
2010-04-28 14:28:56 +02:00
|
|
|
ASSERT(imap->br_startblock != HOLESTARTBLOCK);
|
|
|
|
ASSERT(imap->br_startblock != DELAYSTARTBLOCK);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2010-04-28 14:28:56 +02:00
|
|
|
xfs_map_buffer(inode, bh, imap, offset);
|
2005-04-17 00:20:36 +02:00
|
|
|
set_buffer_mapped(bh);
|
|
|
|
clear_buffer_delay(bh);
|
2006-01-11 05:40:13 +01:00
|
|
|
clear_buffer_unwritten(bh);
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-01-11 10:48:14 +01:00
|
|
|
* Test if a given page is suitable for writing as part of an unwritten
|
|
|
|
* or delayed allocate extent.
|
2005-04-17 00:20:36 +02:00
|
|
|
*/
|
2006-01-11 10:48:14 +01:00
|
|
|
STATIC int
|
2012-04-23 07:58:43 +02:00
|
|
|
xfs_check_page_type(
|
2006-01-11 10:48:14 +01:00
|
|
|
struct page *page,
|
2006-01-11 05:40:13 +01:00
|
|
|
unsigned int type)
|
2005-04-17 00:20:36 +02:00
|
|
|
{
|
|
|
|
if (PageWriteback(page))
|
2006-01-11 10:48:14 +01:00
|
|
|
return 0;
|
2005-04-17 00:20:36 +02: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 05:40:13 +01:00
|
|
|
if (buffer_unwritten(bh))
|
2012-04-23 07:58:43 +02:00
|
|
|
acceptable += (type == IO_UNWRITTEN);
|
2006-01-11 05:40:13 +01:00
|
|
|
else if (buffer_delay(bh))
|
2012-04-23 07:58:43 +02:00
|
|
|
acceptable += (type == IO_DELALLOC);
|
2006-03-22 02:47:40 +01:00
|
|
|
else if (buffer_dirty(bh) && buffer_mapped(bh))
|
2012-04-23 07:58:43 +02:00
|
|
|
acceptable += (type == IO_OVERWRITE);
|
2006-01-11 05:40:13 +01:00
|
|
|
else
|
2005-04-17 00:20:36 +02:00
|
|
|
break;
|
|
|
|
} while ((bh = bh->b_this_page) != head);
|
|
|
|
|
|
|
|
if (acceptable)
|
2006-01-11 10:48:14 +01:00
|
|
|
return 1;
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
|
2006-01-11 10:48:14 +01:00
|
|
|
return 0;
|
2005-04-17 00:20:36 +02: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 05:40:13 +01:00
|
|
|
STATIC int
|
2005-04-17 00:20:36 +02:00
|
|
|
xfs_convert_page(
|
|
|
|
struct inode *inode,
|
|
|
|
struct page *page,
|
2006-01-11 10:48:14 +01:00
|
|
|
loff_t tindex,
|
2010-04-28 14:28:56 +02:00
|
|
|
struct xfs_bmbt_irec *imap,
|
2006-01-11 05:40:13 +01:00
|
|
|
xfs_ioend_t **ioendp,
|
2010-12-10 09:42:23 +01:00
|
|
|
struct writeback_control *wbc)
|
2005-04-17 00:20:36 +02:00
|
|
|
{
|
2006-01-11 05:40:13 +01:00
|
|
|
struct buffer_head *bh, *head;
|
2006-01-11 10:48:47 +01:00
|
|
|
xfs_off_t end_offset;
|
|
|
|
unsigned long p_offset;
|
2006-01-11 05:40:13 +01:00
|
|
|
unsigned int type;
|
2005-05-05 22:33:20 +02:00
|
|
|
int len, page_dirty;
|
2006-01-11 05:40:13 +01:00
|
|
|
int count = 0, done = 0, uptodate = 1;
|
2006-01-11 10:48:47 +01:00
|
|
|
xfs_off_t offset = page_offset(page);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2006-01-11 10:48:14 +01:00
|
|
|
if (page->index != tindex)
|
|
|
|
goto fail;
|
2008-08-02 12:01:03 +02:00
|
|
|
if (!trylock_page(page))
|
2006-01-11 10:48:14 +01:00
|
|
|
goto fail;
|
|
|
|
if (PageWriteback(page))
|
|
|
|
goto fail_unlock_page;
|
|
|
|
if (page->mapping != inode->i_mapping)
|
|
|
|
goto fail_unlock_page;
|
2012-04-23 07:58:43 +02:00
|
|
|
if (!xfs_check_page_type(page, (*ioendp)->io_type))
|
2006-01-11 10:48:14 +01:00
|
|
|
goto fail_unlock_page;
|
|
|
|
|
2005-05-05 22:33:20 +02:00
|
|
|
/*
|
|
|
|
* page_dirty is initially a count of buffers on the page before
|
2006-03-29 00:55:14 +02:00
|
|
|
* EOF and is decremented as we move each into a cleanable state.
|
2006-01-11 10:48:47 +01: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 22:33:20 +02:00
|
|
|
*/
|
2006-01-11 10:48:47 +01:00
|
|
|
end_offset = min_t(unsigned long long,
|
|
|
|
(xfs_off_t)(page->index + 1) << PAGE_CACHE_SHIFT,
|
|
|
|
i_size_read(inode));
|
|
|
|
|
2005-05-05 22:33:20 +02:00
|
|
|
len = 1 << inode->i_blkbits;
|
2006-01-11 10:48:47 +01: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 22:33:20 +02:00
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
bh = head = page_buffers(page);
|
|
|
|
do {
|
2006-01-11 10:48:47 +01:00
|
|
|
if (offset >= end_offset)
|
2005-04-17 00:20:36 +02:00
|
|
|
break;
|
2006-01-11 05:40:13 +01:00
|
|
|
if (!buffer_uptodate(bh))
|
|
|
|
uptodate = 0;
|
|
|
|
if (!(PageUptodate(page) || buffer_uptodate(bh))) {
|
|
|
|
done = 1;
|
2005-04-17 00:20:36 +02:00
|
|
|
continue;
|
2006-01-11 05:40:13 +01:00
|
|
|
}
|
|
|
|
|
2010-12-10 09:42:23 +01:00
|
|
|
if (buffer_unwritten(bh) || buffer_delay(bh) ||
|
|
|
|
buffer_mapped(bh)) {
|
2006-01-11 10:48:47 +01:00
|
|
|
if (buffer_unwritten(bh))
|
2010-04-28 14:28:57 +02:00
|
|
|
type = IO_UNWRITTEN;
|
2010-12-10 09:42:23 +01:00
|
|
|
else if (buffer_delay(bh))
|
2010-12-10 09:42:20 +01:00
|
|
|
type = IO_DELALLOC;
|
2010-12-10 09:42:23 +01:00
|
|
|
else
|
|
|
|
type = IO_OVERWRITE;
|
2006-01-11 10:48:47 +01:00
|
|
|
|
2010-04-28 14:28:58 +02:00
|
|
|
if (!xfs_imap_valid(inode, imap, offset)) {
|
2006-01-11 05:40:13 +01:00
|
|
|
done = 1;
|
2006-01-11 10:48:47 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-12-10 09:42:25 +01:00
|
|
|
lock_buffer(bh);
|
|
|
|
if (type != IO_OVERWRITE)
|
2010-12-10 09:42:23 +01:00
|
|
|
xfs_map_at_offset(inode, bh, imap, offset);
|
2010-06-24 01:45:48 +02:00
|
|
|
xfs_add_to_ioend(inode, bh, offset, type,
|
|
|
|
ioendp, done);
|
|
|
|
|
2006-01-11 10:48:47 +01:00
|
|
|
page_dirty--;
|
|
|
|
count++;
|
|
|
|
} else {
|
2010-12-10 09:42:23 +01:00
|
|
|
done = 1;
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
2006-01-11 10:49:16 +01:00
|
|
|
} while (offset += len, (bh = bh->b_this_page) != head);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2006-01-11 05:40:13 +01:00
|
|
|
if (uptodate && bh == head)
|
|
|
|
SetPageUptodate(page);
|
|
|
|
|
2010-06-24 01:45:48 +02:00
|
|
|
if (count) {
|
2010-08-24 03:44:56 +02:00
|
|
|
if (--wbc->nr_to_write <= 0 &&
|
|
|
|
wbc->sync_mode == WB_SYNC_NONE)
|
2010-06-24 01:45:48 +02:00
|
|
|
done = 1;
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
2010-06-24 01:45:48 +02:00
|
|
|
xfs_start_page_writeback(page, !page_dirty, count);
|
2006-01-11 05:40:13 +01:00
|
|
|
|
|
|
|
return done;
|
2006-01-11 10:48:14 +01:00
|
|
|
fail_unlock_page:
|
|
|
|
unlock_page(page);
|
|
|
|
fail:
|
|
|
|
return 1;
|
2005-04-17 00:20:36 +02: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 14:28:56 +02:00
|
|
|
struct xfs_bmbt_irec *imap,
|
2006-01-11 05:40:13 +01:00
|
|
|
xfs_ioend_t **ioendp,
|
2005-04-17 00:20:36 +02:00
|
|
|
struct writeback_control *wbc,
|
|
|
|
pgoff_t tlast)
|
|
|
|
{
|
2006-01-11 10:48:14 +01:00
|
|
|
struct pagevec pvec;
|
|
|
|
int done = 0, i;
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2006-01-11 10:48:14 +01: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-17 00:20:36 +02:00
|
|
|
break;
|
2006-01-11 10:48:14 +01:00
|
|
|
|
|
|
|
for (i = 0; i < pagevec_count(&pvec); i++) {
|
|
|
|
done = xfs_convert_page(inode, pvec.pages[i], tindex++,
|
2010-12-10 09:42:23 +01:00
|
|
|
imap, ioendp, wbc);
|
2006-01-11 10:48:14 +01:00
|
|
|
if (done)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pagevec_release(&pvec);
|
|
|
|
cond_resched();
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-05 03:00:42 +01: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);
|
|
|
|
|
2012-04-23 07:58:43 +02:00
|
|
|
if (!xfs_check_page_type(page, IO_DELALLOC))
|
2010-03-05 03:00:42 +01:00
|
|
|
goto out_invalidate;
|
|
|
|
|
2010-03-15 03:36:35 +01:00
|
|
|
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
|
|
|
|
goto out_invalidate;
|
|
|
|
|
2011-03-07 00:00:35 +01:00
|
|
|
xfs_alert(ip->i_mount,
|
2010-03-05 03:00:42 +01:00
|
|
|
"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 error;
|
2010-11-30 05:14:39 +01:00
|
|
|
xfs_fileoff_t start_fsb;
|
2010-03-05 03:00:42 +01:00
|
|
|
|
|
|
|
if (!buffer_delay(bh))
|
|
|
|
goto next_buffer;
|
|
|
|
|
2010-11-30 05:14:39 +01:00
|
|
|
start_fsb = XFS_B_TO_FSBT(ip->i_mount, offset);
|
|
|
|
error = xfs_bmap_punch_delalloc_range(ip, start_fsb, 1);
|
2010-03-05 03:00:42 +01:00
|
|
|
if (error) {
|
|
|
|
/* something screwed, just bail */
|
2010-03-15 03:36:35 +01:00
|
|
|
if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
|
2011-03-07 00:00:35 +01:00
|
|
|
xfs_alert(ip->i_mount,
|
2010-03-05 03:00:42 +01:00
|
|
|
"page discard unable to remove delalloc mapping.");
|
2010-03-15 03:36:35 +01:00
|
|
|
}
|
2010-03-05 03:00:42 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
next_buffer:
|
2010-11-30 05:14:39 +01:00
|
|
|
offset += 1 << inode->i_blkbits;
|
2010-03-05 03:00:42 +01:00
|
|
|
|
|
|
|
} while ((bh = bh->b_this_page) != head);
|
|
|
|
|
|
|
|
xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
|
|
|
out_invalidate:
|
|
|
|
xfs_vm_invalidatepage(page, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
/*
|
2010-06-24 01:45:48 +02:00
|
|
|
* Write out a dirty page.
|
|
|
|
*
|
|
|
|
* For delalloc space on the page we need to allocate space and flush it.
|
|
|
|
* For unwritten space on the page we need to start the conversion to
|
|
|
|
* regular allocated space.
|
|
|
|
* For any other dirty buffer heads on the page we should flush them.
|
2005-04-17 00:20:36 +02:00
|
|
|
*/
|
|
|
|
STATIC int
|
2010-06-24 01:45:48 +02:00
|
|
|
xfs_vm_writepage(
|
|
|
|
struct page *page,
|
|
|
|
struct writeback_control *wbc)
|
2005-04-17 00:20:36 +02:00
|
|
|
{
|
2010-06-24 01:45:48 +02:00
|
|
|
struct inode *inode = page->mapping->host;
|
2006-01-11 05:40:13 +01:00
|
|
|
struct buffer_head *bh, *head;
|
2010-04-28 14:28:56 +02:00
|
|
|
struct xfs_bmbt_irec imap;
|
2006-01-11 05:40:13 +01:00
|
|
|
xfs_ioend_t *ioend = NULL, *iohead = NULL;
|
2005-04-17 00:20:36 +02:00
|
|
|
loff_t offset;
|
2006-01-11 05:40:13 +01:00
|
|
|
unsigned int type;
|
2005-04-17 00:20:36 +02:00
|
|
|
__uint64_t end_offset;
|
2010-04-28 14:29:00 +02:00
|
|
|
pgoff_t end_index, last_index;
|
2010-12-10 09:42:22 +01:00
|
|
|
ssize_t len;
|
2010-12-10 09:42:20 +01:00
|
|
|
int err, imap_valid = 0, uptodate = 1;
|
2010-06-24 01:45:48 +02:00
|
|
|
int count = 0;
|
2010-12-10 09:42:20 +01:00
|
|
|
int nonblocking = 0;
|
2010-06-24 01:45:48 +02:00
|
|
|
|
|
|
|
trace_xfs_writepage(inode, page, 0);
|
|
|
|
|
2010-06-24 01:46:01 +02:00
|
|
|
ASSERT(page_has_buffers(page));
|
|
|
|
|
2010-06-24 01:45:48 +02:00
|
|
|
/*
|
|
|
|
* Refuse to write the page out if we are called from reclaim context.
|
|
|
|
*
|
2010-06-28 16:34:44 +02:00
|
|
|
* This avoids stack overflows when called from deeply used stacks in
|
|
|
|
* random callers for direct reclaim or memcg reclaim. We explicitly
|
|
|
|
* allow reclaim from kswapd as the stack usage there is relatively low.
|
2010-06-24 01:45:48 +02:00
|
|
|
*
|
2011-11-01 01:07:45 +01:00
|
|
|
* This should never happen except in the case of a VM regression so
|
|
|
|
* warn about it.
|
2010-06-24 01:45:48 +02:00
|
|
|
*/
|
2011-11-01 01:07:45 +01:00
|
|
|
if (WARN_ON_ONCE((current->flags & (PF_MEMALLOC|PF_KSWAPD)) ==
|
|
|
|
PF_MEMALLOC))
|
2010-08-24 03:47:51 +02:00
|
|
|
goto redirty;
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2010-06-24 01:45:48 +02:00
|
|
|
/*
|
2011-07-08 14:34:05 +02:00
|
|
|
* Given that we do not allow direct reclaim to call us, we should
|
|
|
|
* never be called while in a filesystem transaction.
|
2010-06-24 01:45:48 +02:00
|
|
|
*/
|
2011-07-08 14:34:05 +02:00
|
|
|
if (WARN_ON(current->flags & PF_FSTRANS))
|
2010-08-24 03:47:51 +02:00
|
|
|
goto redirty;
|
2010-06-24 01:45:48 +02:00
|
|
|
|
2005-04-17 00:20:36 +02: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))) {
|
2010-06-24 01:45:48 +02:00
|
|
|
unlock_page(page);
|
2005-11-02 05:14:09 +01:00
|
|
|
return 0;
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-11 05:40:13 +01:00
|
|
|
end_offset = min_t(unsigned long long,
|
2010-06-24 01:46:01 +02:00
|
|
|
(xfs_off_t)(page->index + 1) << PAGE_CACHE_SHIFT,
|
|
|
|
offset);
|
2005-05-05 22:33:20 +02:00
|
|
|
len = 1 << inode->i_blkbits;
|
|
|
|
|
|
|
|
bh = head = page_buffers(page);
|
2006-01-11 05:40:13 +01:00
|
|
|
offset = page_offset(page);
|
2010-12-10 09:42:20 +01:00
|
|
|
type = IO_OVERWRITE;
|
|
|
|
|
2011-07-08 14:34:14 +02:00
|
|
|
if (wbc->sync_mode == WB_SYNC_NONE)
|
2010-12-10 09:42:20 +01:00
|
|
|
nonblocking = 1;
|
2006-01-11 05:40:13 +01:00
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
do {
|
2010-12-10 09:42:18 +01:00
|
|
|
int new_ioend = 0;
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
if (offset >= end_offset)
|
|
|
|
break;
|
|
|
|
if (!buffer_uptodate(bh))
|
|
|
|
uptodate = 0;
|
|
|
|
|
2010-06-24 01:45:30 +02:00
|
|
|
/*
|
2010-11-10 22:39:11 +01:00
|
|
|
* set_page_dirty dirties all buffers in a page, independent
|
|
|
|
* of their state. The dirty state however is entirely
|
|
|
|
* meaningless for holes (!mapped && uptodate), so skip
|
|
|
|
* buffers covering holes here.
|
2010-06-24 01:45:30 +02:00
|
|
|
*/
|
|
|
|
if (!buffer_mapped(bh) && buffer_uptodate(bh)) {
|
|
|
|
imap_valid = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-12-10 09:42:24 +01:00
|
|
|
if (buffer_unwritten(bh)) {
|
|
|
|
if (type != IO_UNWRITTEN) {
|
|
|
|
type = IO_UNWRITTEN;
|
|
|
|
imap_valid = 0;
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
2010-12-10 09:42:24 +01:00
|
|
|
} else if (buffer_delay(bh)) {
|
|
|
|
if (type != IO_DELALLOC) {
|
|
|
|
type = IO_DELALLOC;
|
|
|
|
imap_valid = 0;
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
2010-06-24 01:45:48 +02:00
|
|
|
} else if (buffer_uptodate(bh)) {
|
2010-12-10 09:42:20 +01:00
|
|
|
if (type != IO_OVERWRITE) {
|
|
|
|
type = IO_OVERWRITE;
|
2010-12-10 09:42:16 +01:00
|
|
|
imap_valid = 0;
|
|
|
|
}
|
2010-12-10 09:42:24 +01:00
|
|
|
} else {
|
|
|
|
if (PageUptodate(page)) {
|
|
|
|
ASSERT(buffer_mapped(bh));
|
|
|
|
imap_valid = 0;
|
2006-01-11 10:49:28 +01:00
|
|
|
}
|
2010-12-10 09:42:24 +01:00
|
|
|
continue;
|
|
|
|
}
|
2006-01-11 10:49:02 +01:00
|
|
|
|
2010-12-10 09:42:24 +01:00
|
|
|
if (imap_valid)
|
|
|
|
imap_valid = xfs_imap_valid(inode, &imap, offset);
|
|
|
|
if (!imap_valid) {
|
|
|
|
/*
|
|
|
|
* If we didn't have a valid mapping then we need to
|
|
|
|
* put the new mapping into a separate ioend structure.
|
|
|
|
* This ensures non-contiguous extents always have
|
|
|
|
* separate ioends, which is particularly important
|
|
|
|
* for unwritten extent conversion at I/O completion
|
|
|
|
* time.
|
|
|
|
*/
|
|
|
|
new_ioend = 1;
|
|
|
|
err = xfs_map_blocks(inode, offset, &imap, type,
|
|
|
|
nonblocking);
|
|
|
|
if (err)
|
|
|
|
goto error;
|
|
|
|
imap_valid = xfs_imap_valid(inode, &imap, offset);
|
|
|
|
}
|
|
|
|
if (imap_valid) {
|
2010-12-10 09:42:25 +01:00
|
|
|
lock_buffer(bh);
|
|
|
|
if (type != IO_OVERWRITE)
|
2010-12-10 09:42:24 +01:00
|
|
|
xfs_map_at_offset(inode, bh, &imap, offset);
|
|
|
|
xfs_add_to_ioend(inode, bh, offset, type, &ioend,
|
|
|
|
new_ioend);
|
|
|
|
count++;
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
2006-01-11 05:40:13 +01:00
|
|
|
|
|
|
|
if (!iohead)
|
|
|
|
iohead = ioend;
|
|
|
|
|
|
|
|
} while (offset += len, ((bh = bh->b_this_page) != head));
|
2005-04-17 00:20:36 +02:00
|
|
|
|
|
|
|
if (uptodate && bh == head)
|
|
|
|
SetPageUptodate(page);
|
|
|
|
|
2010-06-24 01:45:48 +02:00
|
|
|
xfs_start_page_writeback(page, 1, count);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2010-04-28 14:28:58 +02:00
|
|
|
if (ioend && imap_valid) {
|
2010-04-28 14:29:00 +02: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 14:28:54 +02:00
|
|
|
|
2010-04-28 14:28:56 +02:00
|
|
|
xfs_cluster_write(inode, page->index + 1, &imap, &ioend,
|
2010-12-10 09:42:23 +01:00
|
|
|
wbc, end_index);
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
|
2012-03-13 09:41:05 +01:00
|
|
|
if (iohead) {
|
|
|
|
/*
|
|
|
|
* Reserve log space if we might write beyond the on-disk
|
|
|
|
* inode size.
|
|
|
|
*/
|
|
|
|
if (ioend->io_type != IO_UNWRITTEN &&
|
|
|
|
xfs_ioend_is_append(ioend)) {
|
|
|
|
err = xfs_setfilesize_trans_alloc(ioend);
|
|
|
|
if (err)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2009-10-30 10:09:15 +01:00
|
|
|
xfs_submit_ioend(wbc, iohead);
|
2012-03-13 09:41:05 +01:00
|
|
|
}
|
2006-01-11 05:40:13 +01:00
|
|
|
|
2010-06-24 01:45:48 +02:00
|
|
|
return 0;
|
2005-04-17 00:20:36 +02:00
|
|
|
|
|
|
|
error:
|
2006-01-11 05:40:13 +01:00
|
|
|
if (iohead)
|
|
|
|
xfs_cancel_ioend(iohead);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2010-08-24 03:47:51 +02:00
|
|
|
if (err == -EAGAIN)
|
|
|
|
goto redirty;
|
|
|
|
|
2010-06-24 01:46:01 +02:00
|
|
|
xfs_aops_discard_page(page);
|
2010-06-24 01:45:48 +02:00
|
|
|
ClearPageUptodate(page);
|
|
|
|
unlock_page(page);
|
2005-04-17 00:20:36 +02:00
|
|
|
return err;
|
2006-03-14 03:26:27 +01:00
|
|
|
|
2010-08-24 03:47:51 +02:00
|
|
|
redirty:
|
2006-03-14 03:26:27 +01:00
|
|
|
redirty_page_for_writepage(wbc, page);
|
|
|
|
unlock_page(page);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-06-09 07:27:16 +02:00
|
|
|
STATIC int
|
|
|
|
xfs_vm_writepages(
|
|
|
|
struct address_space *mapping,
|
|
|
|
struct writeback_control *wbc)
|
|
|
|
{
|
2007-08-29 03:44:37 +02:00
|
|
|
xfs_iflags_clear(XFS_I(mapping->host), XFS_ITRUNCATED);
|
2006-06-09 07:27:16 +02:00
|
|
|
return generic_writepages(mapping, wbc);
|
|
|
|
}
|
|
|
|
|
2006-03-14 03:26:27 +01:00
|
|
|
/*
|
|
|
|
* Called to move a page into cleanable state - and from there
|
2010-06-24 01:45:48 +02:00
|
|
|
* to be released. The page should already be clean. We always
|
2006-03-14 03:26:27 +01:00
|
|
|
* have buffer heads in this call.
|
|
|
|
*
|
2010-06-24 01:45:48 +02:00
|
|
|
* Returns 1 if the page is ok to release, 0 otherwise.
|
2006-03-14 03:26:27 +01:00
|
|
|
*/
|
|
|
|
STATIC int
|
2006-03-17 07:26:25 +01:00
|
|
|
xfs_vm_releasepage(
|
2006-03-14 03:26:27 +01:00
|
|
|
struct page *page,
|
|
|
|
gfp_t gfp_mask)
|
|
|
|
{
|
2010-06-24 01:46:01 +02:00
|
|
|
int delalloc, unwritten;
|
2006-03-14 03:26:27 +01:00
|
|
|
|
2010-06-24 01:45:48 +02:00
|
|
|
trace_xfs_releasepage(page->mapping->host, page, 0);
|
2006-03-17 07:26:25 +01:00
|
|
|
|
2010-06-24 01:46:01 +02:00
|
|
|
xfs_count_page_state(page, &delalloc, &unwritten);
|
2006-03-14 03:26:27 +01:00
|
|
|
|
2010-06-24 01:45:48 +02:00
|
|
|
if (WARN_ON(delalloc))
|
2006-03-14 03:26:27 +01:00
|
|
|
return 0;
|
2010-06-24 01:45:48 +02:00
|
|
|
if (WARN_ON(unwritten))
|
2006-03-14 03:26:27 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return try_to_free_buffers(page);
|
|
|
|
}
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
STATIC int
|
2006-03-29 02:44:40 +02:00
|
|
|
__xfs_get_blocks(
|
2005-04-17 00:20:36 +02:00
|
|
|
struct inode *inode,
|
|
|
|
sector_t iblock,
|
|
|
|
struct buffer_head *bh_result,
|
|
|
|
int create,
|
2010-06-24 03:44:35 +02:00
|
|
|
int direct)
|
2005-04-17 00:20:36 +02:00
|
|
|
{
|
2010-12-10 09:42:20 +01:00
|
|
|
struct xfs_inode *ip = XFS_I(inode);
|
|
|
|
struct xfs_mount *mp = ip->i_mount;
|
|
|
|
xfs_fileoff_t offset_fsb, end_fsb;
|
|
|
|
int error = 0;
|
|
|
|
int lockmode = 0;
|
2010-04-28 14:28:56 +02:00
|
|
|
struct xfs_bmbt_irec imap;
|
2010-12-10 09:42:20 +01:00
|
|
|
int nimaps = 1;
|
2005-11-02 05:13:13 +01:00
|
|
|
xfs_off_t offset;
|
|
|
|
ssize_t size;
|
2010-04-28 14:28:56 +02:00
|
|
|
int new = 0;
|
2010-12-10 09:42:20 +01:00
|
|
|
|
|
|
|
if (XFS_FORCED_SHUTDOWN(mp))
|
|
|
|
return -XFS_ERROR(EIO);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2005-11-02 05:13:13 +01:00
|
|
|
offset = (xfs_off_t)iblock << inode->i_blkbits;
|
2006-03-29 02:44:40 +02:00
|
|
|
ASSERT(bh_result->b_size >= (1 << inode->i_blkbits));
|
|
|
|
size = bh_result->b_size;
|
2008-09-17 08:50:14 +02:00
|
|
|
|
|
|
|
if (!create && direct && offset >= i_size_read(inode))
|
|
|
|
return 0;
|
|
|
|
|
2012-03-27 16:34:50 +02:00
|
|
|
/*
|
|
|
|
* Direct I/O is usually done on preallocated files, so try getting
|
|
|
|
* a block mapping without an exclusive lock first. For buffered
|
|
|
|
* writes we already have the exclusive iolock anyway, so avoiding
|
|
|
|
* a lock roundtrip here by taking the ilock exclusive from the
|
|
|
|
* beginning is a useful micro optimization.
|
|
|
|
*/
|
|
|
|
if (create && !direct) {
|
2010-12-10 09:42:20 +01:00
|
|
|
lockmode = XFS_ILOCK_EXCL;
|
|
|
|
xfs_ilock(ip, lockmode);
|
|
|
|
} else {
|
|
|
|
lockmode = xfs_ilock_map_shared(ip);
|
|
|
|
}
|
2010-06-24 03:44:35 +02:00
|
|
|
|
2010-12-10 09:42:20 +01:00
|
|
|
ASSERT(offset <= mp->m_maxioffset);
|
|
|
|
if (offset + size > mp->m_maxioffset)
|
|
|
|
size = mp->m_maxioffset - offset;
|
|
|
|
end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + size);
|
|
|
|
offset_fsb = XFS_B_TO_FSBT(mp, offset);
|
|
|
|
|
2011-09-18 22:40:45 +02:00
|
|
|
error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb,
|
|
|
|
&imap, &nimaps, XFS_BMAPI_ENTIRE);
|
2005-04-17 00:20:36 +02:00
|
|
|
if (error)
|
2010-12-10 09:42:20 +01:00
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
if (create &&
|
|
|
|
(!nimaps ||
|
|
|
|
(imap.br_startblock == HOLESTARTBLOCK ||
|
|
|
|
imap.br_startblock == DELAYSTARTBLOCK))) {
|
|
|
|
if (direct) {
|
2012-03-27 16:34:50 +02:00
|
|
|
/*
|
|
|
|
* Drop the ilock in preparation for starting the block
|
|
|
|
* allocation transaction. It will be retaken
|
|
|
|
* exclusively inside xfs_iomap_write_direct for the
|
|
|
|
* actual allocation.
|
|
|
|
*/
|
|
|
|
xfs_iunlock(ip, lockmode);
|
2010-12-10 09:42:20 +01:00
|
|
|
error = xfs_iomap_write_direct(ip, offset, size,
|
|
|
|
&imap, nimaps);
|
2012-03-27 16:34:50 +02:00
|
|
|
if (error)
|
|
|
|
return -error;
|
2010-12-10 09:42:20 +01:00
|
|
|
} else {
|
2012-03-27 16:34:50 +02:00
|
|
|
/*
|
|
|
|
* Delalloc reservations do not require a transaction,
|
|
|
|
* we can go on without dropping the lock here.
|
|
|
|
*/
|
2010-12-10 09:42:20 +01:00
|
|
|
error = xfs_iomap_write_delay(ip, offset, size, &imap);
|
2012-03-27 16:34:50 +02:00
|
|
|
if (error)
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
xfs_iunlock(ip, lockmode);
|
2010-12-10 09:42:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
trace_xfs_get_blocks_alloc(ip, offset, size, 0, &imap);
|
|
|
|
} else if (nimaps) {
|
|
|
|
trace_xfs_get_blocks_found(ip, offset, size, 0, &imap);
|
2012-03-27 16:34:50 +02:00
|
|
|
xfs_iunlock(ip, lockmode);
|
2010-12-10 09:42:20 +01:00
|
|
|
} else {
|
|
|
|
trace_xfs_get_blocks_notfound(ip, offset, size);
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2010-04-28 14:28:56 +02:00
|
|
|
if (imap.br_startblock != HOLESTARTBLOCK &&
|
|
|
|
imap.br_startblock != DELAYSTARTBLOCK) {
|
2006-03-14 03:26:43 +01:00
|
|
|
/*
|
|
|
|
* For unwritten extents do not report a disk address on
|
2005-04-17 00:20:36 +02:00
|
|
|
* the read case (treat as if we're reading into a hole).
|
|
|
|
*/
|
2010-04-28 14:28:56 +02:00
|
|
|
if (create || !ISUNWRITTEN(&imap))
|
|
|
|
xfs_map_buffer(inode, bh_result, &imap, offset);
|
|
|
|
if (create && ISUNWRITTEN(&imap)) {
|
2005-04-17 00:20:36 +02:00
|
|
|
if (direct)
|
|
|
|
bh_result->b_private = inode;
|
|
|
|
set_buffer_unwritten(bh_result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-29 02:44:40 +02: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 14:28:52 +02:00
|
|
|
bh_result->b_bdev = xfs_find_bdev_for_inode(inode);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2006-03-29 02:44:40 +02:00
|
|
|
/*
|
2007-02-10 08:36:35 +01: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-17 00:20:36 +02:00
|
|
|
*/
|
|
|
|
if (create &&
|
|
|
|
((!buffer_mapped(bh_result) && !buffer_uptodate(bh_result)) ||
|
2007-02-10 08:36:35 +01:00
|
|
|
(offset >= i_size_read(inode)) ||
|
2010-04-28 14:28:56 +02:00
|
|
|
(new || ISUNWRITTEN(&imap))))
|
2005-04-17 00:20:36 +02:00
|
|
|
set_buffer_new(bh_result);
|
|
|
|
|
2010-04-28 14:28:56 +02:00
|
|
|
if (imap.br_startblock == DELAYSTARTBLOCK) {
|
2005-04-17 00:20:36 +02:00
|
|
|
BUG_ON(direct);
|
|
|
|
if (create) {
|
|
|
|
set_buffer_uptodate(bh_result);
|
|
|
|
set_buffer_mapped(bh_result);
|
|
|
|
set_buffer_delay(bh_result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-28 14:28:59 +02: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 02:44:40 +02:00
|
|
|
if (direct || size > (1 << inode->i_blkbits)) {
|
2010-04-28 14:28:59 +02: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-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2010-12-10 09:42:20 +01:00
|
|
|
|
|
|
|
out_unlock:
|
|
|
|
xfs_iunlock(ip, lockmode);
|
|
|
|
return -error;
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2006-03-29 02:44:40 +02:00
|
|
|
xfs_get_blocks(
|
2005-04-17 00:20:36 +02:00
|
|
|
struct inode *inode,
|
|
|
|
sector_t iblock,
|
|
|
|
struct buffer_head *bh_result,
|
|
|
|
int create)
|
|
|
|
{
|
2010-06-24 03:44:35 +02:00
|
|
|
return __xfs_get_blocks(inode, iblock, bh_result, create, 0);
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
STATIC int
|
2006-03-14 03:54:26 +01:00
|
|
|
xfs_get_blocks_direct(
|
2005-04-17 00:20:36 +02:00
|
|
|
struct inode *inode,
|
|
|
|
sector_t iblock,
|
|
|
|
struct buffer_head *bh_result,
|
|
|
|
int create)
|
|
|
|
{
|
2010-06-24 03:44:35 +02:00
|
|
|
return __xfs_get_blocks(inode, iblock, bh_result, create, 1);
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
|
2010-07-18 23:17:11 +02:00
|
|
|
/*
|
|
|
|
* Complete a direct I/O write request.
|
|
|
|
*
|
|
|
|
* If the private argument is non-NULL __xfs_get_blocks signals us that we
|
|
|
|
* need to issue a transaction to convert the range from unwritten to written
|
|
|
|
* extents. In case this is regular synchronous I/O we just call xfs_end_io
|
2011-03-31 03:57:33 +02:00
|
|
|
* to do this and we are done. But in case this was a successful AIO
|
2010-07-18 23:17:11 +02:00
|
|
|
* request this handler is called from interrupt context, from which we
|
|
|
|
* can't start transactions. In that case offload the I/O completion to
|
|
|
|
* the workqueues we also use for buffered I/O completion.
|
|
|
|
*/
|
2005-09-05 00:22:52 +02:00
|
|
|
STATIC void
|
2010-07-18 23:17:11 +02:00
|
|
|
xfs_end_io_direct_write(
|
|
|
|
struct kiocb *iocb,
|
|
|
|
loff_t offset,
|
|
|
|
ssize_t size,
|
|
|
|
void *private,
|
|
|
|
int ret,
|
|
|
|
bool is_async)
|
2005-09-05 00:22:52 +02:00
|
|
|
{
|
2010-07-18 23:17:11 +02:00
|
|
|
struct xfs_ioend *ioend = iocb->private;
|
2005-09-05 00:22:52 +02:00
|
|
|
|
2011-12-18 21:00:12 +01:00
|
|
|
/*
|
|
|
|
* While the generic direct I/O code updates the inode size, it does
|
|
|
|
* so only after the end_io handler is called, which means our
|
|
|
|
* end_io handler thinks the on-disk size is outside the in-core
|
|
|
|
* size. To prevent this just update it a little bit earlier here.
|
|
|
|
*/
|
|
|
|
if (offset + size > i_size_read(ioend->io_inode))
|
|
|
|
i_size_write(ioend->io_inode, offset + size);
|
|
|
|
|
2005-09-05 00:22:52 +02:00
|
|
|
/*
|
2010-07-18 23:17:11 +02:00
|
|
|
* blockdev_direct_IO can return an error even after the I/O
|
|
|
|
* completion handler was called. Thus we need to protect
|
|
|
|
* against double-freeing.
|
2005-09-05 00:22:52 +02:00
|
|
|
*/
|
2010-07-18 23:17:11 +02:00
|
|
|
iocb->private = NULL;
|
|
|
|
|
[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 05:49:46 +02:00
|
|
|
ioend->io_offset = offset;
|
|
|
|
ioend->io_size = size;
|
2011-08-23 10:28:10 +02:00
|
|
|
ioend->io_iocb = iocb;
|
|
|
|
ioend->io_result = ret;
|
2010-07-18 23:17:11 +02:00
|
|
|
if (private && size > 0)
|
|
|
|
ioend->io_type = IO_UNWRITTEN;
|
|
|
|
|
|
|
|
if (is_async) {
|
2011-08-23 10:28:10 +02:00
|
|
|
ioend->io_isasync = 1;
|
2010-07-18 23:17:11 +02:00
|
|
|
xfs_finish_ioend(ioend);
|
2005-09-05 00:22:52 +02:00
|
|
|
} else {
|
2010-07-18 23:17:11 +02:00
|
|
|
xfs_finish_ioend_sync(ioend);
|
2005-09-05 00:22:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
STATIC ssize_t
|
2006-03-14 03:54:26 +01:00
|
|
|
xfs_vm_direct_IO(
|
2005-04-17 00:20:36 +02:00
|
|
|
int rw,
|
|
|
|
struct kiocb *iocb,
|
|
|
|
const struct iovec *iov,
|
|
|
|
loff_t offset,
|
|
|
|
unsigned long nr_segs)
|
|
|
|
{
|
2010-07-18 23:17:11 +02:00
|
|
|
struct inode *inode = iocb->ki_filp->f_mapping->host;
|
|
|
|
struct block_device *bdev = xfs_find_bdev_for_inode(inode);
|
2012-03-13 09:41:05 +01:00
|
|
|
struct xfs_ioend *ioend = NULL;
|
2010-07-18 23:17:11 +02:00
|
|
|
ssize_t ret;
|
|
|
|
|
|
|
|
if (rw & WRITE) {
|
2012-03-13 09:41:05 +01:00
|
|
|
size_t size = iov_length(iov, nr_segs);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We need to preallocate a transaction for a size update
|
|
|
|
* here. In the case that this write both updates the size
|
|
|
|
* and converts at least on unwritten extent we will cancel
|
|
|
|
* the still clean transaction after the I/O has finished.
|
|
|
|
*/
|
|
|
|
iocb->private = ioend = xfs_alloc_ioend(inode, IO_DIRECT);
|
|
|
|
if (offset + size > XFS_I(inode)->i_d.di_size) {
|
|
|
|
ret = xfs_setfilesize_trans_alloc(ioend);
|
|
|
|
if (ret)
|
|
|
|
goto out_destroy_ioend;
|
|
|
|
ioend->io_isdirect = 1;
|
|
|
|
}
|
2010-07-18 23:17:11 +02:00
|
|
|
|
2010-06-04 11:29:53 +02:00
|
|
|
ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov,
|
|
|
|
offset, nr_segs,
|
|
|
|
xfs_get_blocks_direct,
|
|
|
|
xfs_end_io_direct_write, NULL, 0);
|
2010-07-18 23:17:11 +02:00
|
|
|
if (ret != -EIOCBQUEUED && iocb->private)
|
2012-03-13 09:41:05 +01:00
|
|
|
goto out_trans_cancel;
|
2010-07-18 23:17:11 +02:00
|
|
|
} else {
|
2010-06-04 11:29:53 +02:00
|
|
|
ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov,
|
|
|
|
offset, nr_segs,
|
|
|
|
xfs_get_blocks_direct,
|
|
|
|
NULL, NULL, 0);
|
2010-07-18 23:17:11 +02:00
|
|
|
}
|
2005-09-05 00:22:52 +02:00
|
|
|
|
|
|
|
return ret;
|
2012-03-13 09:41:05 +01:00
|
|
|
|
|
|
|
out_trans_cancel:
|
|
|
|
if (ioend->io_append_trans) {
|
|
|
|
current_set_flags_nested(&ioend->io_append_trans->t_pflags,
|
|
|
|
PF_FSTRANS);
|
|
|
|
xfs_trans_cancel(ioend->io_append_trans, 0);
|
|
|
|
}
|
|
|
|
out_destroy_ioend:
|
|
|
|
xfs_destroy_ioend(ioend);
|
|
|
|
return ret;
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
|
2010-06-14 11:17:31 +02:00
|
|
|
STATIC void
|
|
|
|
xfs_vm_write_failed(
|
|
|
|
struct address_space *mapping,
|
|
|
|
loff_t to)
|
|
|
|
{
|
|
|
|
struct inode *inode = mapping->host;
|
|
|
|
|
|
|
|
if (to > inode->i_size) {
|
2010-11-30 05:14:39 +01:00
|
|
|
/*
|
2011-12-18 21:00:12 +01:00
|
|
|
* Punch out the delalloc blocks we have already allocated.
|
|
|
|
*
|
|
|
|
* Don't bother with xfs_setattr given that nothing can have
|
|
|
|
* made it to disk yet as the page is still locked at this
|
|
|
|
* point.
|
2010-11-30 05:14:39 +01:00
|
|
|
*/
|
|
|
|
struct xfs_inode *ip = XFS_I(inode);
|
|
|
|
xfs_fileoff_t start_fsb;
|
|
|
|
xfs_fileoff_t end_fsb;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
truncate_pagecache(inode, to, inode->i_size);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if there are any blocks that are outside of i_size
|
|
|
|
* that need to be trimmed back.
|
|
|
|
*/
|
xfs: punch all delalloc blocks beyond EOF on write failure.
I've been seeing regular ASSERT failures in xfstests when running
fsstress based tests over the past month. xfs_getbmap() has been
failing this test:
XFS: Assertion failed: ((iflags & BMV_IF_DELALLOC) != 0) ||
(map[i].br_startblock != DELAYSTARTBLOCK), file: fs/xfs/xfs_bmap.c,
line: 5650
where it is encountering a delayed allocation extent after writing
all the dirty data to disk and then walking the extent map
atomically by holding the XFS_IOLOCK_SHARED to prevent new delayed
allocation extents from being created.
Test 083 on a 512 byte block size filesystem was used to reproduce
the problem, because it only had a 5s run timeand would usually fail
every 3-4 runs. This test is exercising ENOSPC behaviour by running
fsstress on a nearly full filesystem. The following trace extract
shows the final few events on the inode that tripped the assert:
xfs_ilock: flags ILOCK_EXCL caller xfs_setfilesize
xfs_setfilesize: isize 0x180000 disize 0x12d400 offset 0x17e200 count 7680
file size updated to 0x180000 by IO completion
xfs_ilock: flags ILOCK_EXCL caller xfs_iomap_write_delay
xfs_iext_insert: state idx 3 offset 3072 block 4503599627239432 count 1 flag 0 caller xfs_bmap_add_extent_hole_delay
xfs_get_blocks_alloc: size 0x180000 offset 0x180000 count 512 type startoff 0xc00 startblock -1 blockcount 0x1
xfs_ilock: flags ILOCK_EXCL caller __xfs_get_blocks
delalloc write, adding a single block at offset 0x180000
xfs_delalloc_enospc: isize 0x180000 disize 0x180000 offset 0x180200 count 512
ENOSPC trying to allocate a dellalloc block at offset 0x180200
xfs_ilock: flags ILOCK_EXCL caller xfs_iomap_write_delay
xfs_get_blocks_alloc: size 0x180000 offset 0x180200 count 512 type startoff 0xc00 startblock -1 blockcount 0x2
And succeeding on retry after flushing dirty inodes.
xfs_ilock: flags ILOCK_EXCL caller __xfs_get_blocks
xfs_delalloc_enospc: isize 0x180000 disize 0x180000 offset 0x180400 count 512
ENOSPC trying to allocate a dellalloc block at offset 0x180400
xfs_ilock: flags ILOCK_EXCL caller xfs_iomap_write_delay
xfs_delalloc_enospc: isize 0x180000 disize 0x180000 offset 0x180400 count 512
And failing the retry, giving a real ENOSPC error.
xfs_ilock: flags ILOCK_EXCL caller xfs_vm_write_failed
^^^^^^^^^^^^^^^^^^^
The smoking gun - the write being failed and cleaning up delalloc
blocks beyond EOF allocated by the failed write.
xfs_getattr:
xfs_ilock: flags IOLOCK_SHARED caller xfs_getbmap
xfs_ilock: flags ILOCK_SHARED caller xfs_ilock_map_shared
And that's where we died almost immediately afterwards.
xfs_bmapi_read() found delalloc extent beyond current file in memory
file size. Some debug I added to xfs_getbmap() showed the state just
before the assert failure:
ino 0x80e48: off 0xc00, fsb 0xffffffffffffffff, len 0x1, size 0x180000
start_fsb 0x106, end_fsb 0x638
ino flags 0x2 nex 0xd bmvcnt 0x555, len 0x3c58a6f23c0bf1, start 0xc00
ext 0: off 0x1fc, fsb 0x24782, len 0x254
ext 1: off 0x450, fsb 0x40851, len 0x30
ext 2: off 0x480, fsb 0xd99, len 0x1b8
ext 3: off 0x92f, fsb 0x4099a, len 0x3b
ext 4: off 0x96d, fsb 0x41844, len 0x98
ext 5: off 0xbf1, fsb 0x408ab, len 0xf
which shows that we found a single delalloc block beyond EOF (first
line of output) when we were returning the map for a length
somewhere around 10^16 bytes long (second line), and the on-disk
extents showed they didn't go past EOF (last lines).
Further debug added to xfs_vm_write_failed() showed this happened
when punching out delalloc blocks beyond the end of the file after
the failed write:
[ 132.606693] ino 0x80e48: vwf to 0x181000, sze 0x180000
[ 132.609573] start_fsb 0xc01, end_fsb 0xc08
It punched the range 0xc01 -> 0xc08, but the range we really need to
punch is 0xc00 -> 0xc07 (8 blocks from 0xc00) as this testing was
run on a 512 byte block size filesystem (8 blocks per page).
the punch from is 0xc00. So end_fsb is correct, but start_fsb is
wrong as we punch from start_fsb for (end_fsb - start_fsb) blocks.
Hence we are not punching the delalloc block beyond EOF in the case.
The fix is simple - it's a silly off-by-one mistake in calculating
the range. It's especially silly because the macro used to calculate
the start_fsb already takes into account the case where the inode
size is an exact multiple of the filesystem block size...
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
2012-04-26 01:23:09 +02:00
|
|
|
start_fsb = XFS_B_TO_FSB(ip->i_mount, inode->i_size);
|
2010-11-30 05:14:39 +01:00
|
|
|
end_fsb = XFS_B_TO_FSB(ip->i_mount, to);
|
|
|
|
if (end_fsb <= start_fsb)
|
|
|
|
return;
|
|
|
|
|
|
|
|
xfs_ilock(ip, XFS_ILOCK_EXCL);
|
|
|
|
error = xfs_bmap_punch_delalloc_range(ip, start_fsb,
|
|
|
|
end_fsb - start_fsb);
|
|
|
|
if (error) {
|
|
|
|
/* something screwed, just bail */
|
|
|
|
if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
|
2011-03-07 00:00:35 +01:00
|
|
|
xfs_alert(ip->i_mount,
|
2010-11-30 05:14:39 +01:00
|
|
|
"xfs_vm_write_failed: unable to clean up ino %lld",
|
|
|
|
ip->i_ino);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
2010-06-14 11:17:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-14 03:26:27 +01:00
|
|
|
STATIC int
|
2007-10-16 10:25:06 +02:00
|
|
|
xfs_vm_write_begin(
|
2006-03-14 03:26:27 +01:00
|
|
|
struct file *file,
|
2007-10-16 10:25:06 +02:00
|
|
|
struct address_space *mapping,
|
|
|
|
loff_t pos,
|
|
|
|
unsigned len,
|
|
|
|
unsigned flags,
|
|
|
|
struct page **pagep,
|
|
|
|
void **fsdata)
|
2006-03-14 03:26:27 +01:00
|
|
|
{
|
2010-06-04 11:29:58 +02:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = block_write_begin(mapping, pos, len, flags | AOP_FLAG_NOFS,
|
|
|
|
pagep, xfs_get_blocks);
|
2010-06-14 11:17:31 +02:00
|
|
|
if (unlikely(ret))
|
|
|
|
xfs_vm_write_failed(mapping, pos + len);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC int
|
|
|
|
xfs_vm_write_end(
|
|
|
|
struct file *file,
|
|
|
|
struct address_space *mapping,
|
|
|
|
loff_t pos,
|
|
|
|
unsigned len,
|
|
|
|
unsigned copied,
|
|
|
|
struct page *page,
|
|
|
|
void *fsdata)
|
|
|
|
{
|
|
|
|
int ret;
|
2010-06-04 11:29:58 +02:00
|
|
|
|
2010-06-14 11:17:31 +02:00
|
|
|
ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
|
|
|
|
if (unlikely(ret < len))
|
|
|
|
xfs_vm_write_failed(mapping, pos + len);
|
2010-06-04 11:29:58 +02:00
|
|
|
return ret;
|
2006-03-14 03:26:27 +01:00
|
|
|
}
|
2005-04-17 00:20:36 +02:00
|
|
|
|
|
|
|
STATIC sector_t
|
2006-03-14 03:54:26 +01:00
|
|
|
xfs_vm_bmap(
|
2005-04-17 00:20:36 +02:00
|
|
|
struct address_space *mapping,
|
|
|
|
sector_t block)
|
|
|
|
{
|
|
|
|
struct inode *inode = (struct inode *)mapping->host;
|
2007-08-29 02:58:01 +02:00
|
|
|
struct xfs_inode *ip = XFS_I(inode);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2010-06-24 03:57:09 +02:00
|
|
|
trace_xfs_vm_bmap(XFS_I(inode));
|
2008-03-06 03:44:57 +01:00
|
|
|
xfs_ilock(ip, XFS_IOLOCK_SHARED);
|
2007-08-29 02:58:01 +02:00
|
|
|
xfs_flush_pages(ip, (xfs_off_t)0, -1, 0, FI_REMAPF);
|
2008-03-06 03:44:57 +01:00
|
|
|
xfs_iunlock(ip, XFS_IOLOCK_SHARED);
|
2006-03-29 02:44:40 +02:00
|
|
|
return generic_block_bmap(mapping, block, xfs_get_blocks);
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
STATIC int
|
2006-03-14 03:54:26 +01:00
|
|
|
xfs_vm_readpage(
|
2005-04-17 00:20:36 +02:00
|
|
|
struct file *unused,
|
|
|
|
struct page *page)
|
|
|
|
{
|
2006-03-29 02:44:40 +02:00
|
|
|
return mpage_readpage(page, xfs_get_blocks);
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
STATIC int
|
2006-03-14 03:54:26 +01:00
|
|
|
xfs_vm_readpages(
|
2005-04-17 00:20:36 +02:00
|
|
|
struct file *unused,
|
|
|
|
struct address_space *mapping,
|
|
|
|
struct list_head *pages,
|
|
|
|
unsigned nr_pages)
|
|
|
|
{
|
2006-03-29 02:44:40 +02:00
|
|
|
return mpage_readpages(mapping, pages, nr_pages, xfs_get_blocks);
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
|
2006-06-28 13:26:44 +02:00
|
|
|
const struct address_space_operations xfs_address_space_operations = {
|
2006-03-14 03:54:26 +01:00
|
|
|
.readpage = xfs_vm_readpage,
|
|
|
|
.readpages = xfs_vm_readpages,
|
|
|
|
.writepage = xfs_vm_writepage,
|
2006-06-09 07:27:16 +02:00
|
|
|
.writepages = xfs_vm_writepages,
|
2006-03-17 07:26:25 +01:00
|
|
|
.releasepage = xfs_vm_releasepage,
|
|
|
|
.invalidatepage = xfs_vm_invalidatepage,
|
2007-10-16 10:25:06 +02:00
|
|
|
.write_begin = xfs_vm_write_begin,
|
2010-06-14 11:17:31 +02:00
|
|
|
.write_end = xfs_vm_write_end,
|
2006-03-14 03:54:26 +01:00
|
|
|
.bmap = xfs_vm_bmap,
|
|
|
|
.direct_IO = xfs_vm_direct_IO,
|
2006-02-01 12:05:41 +01:00
|
|
|
.migratepage = buffer_migrate_page,
|
2009-03-29 09:53:38 +02:00
|
|
|
.is_partially_uptodate = block_is_partially_uptodate,
|
2009-09-16 11:50:16 +02:00
|
|
|
.error_remove_page = generic_error_remove_page,
|
2005-04-17 00:20:36 +02:00
|
|
|
};
|