2018-06-06 02:42:14 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
2005-11-02 03:58:39 +00:00
|
|
|
* Copyright (c) 2000-2005 Silicon Graphics, Inc.
|
2018-07-12 05:26:06 +00:00
|
|
|
* Copyright (c) 2016-2018 Christoph Hellwig.
|
2005-11-02 03:58:39 +00:00
|
|
|
* All Rights Reserved.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
|
|
|
#include "xfs.h"
|
2013-10-22 23:36:05 +00:00
|
|
|
#include "xfs_shared.h"
|
2013-10-22 23:50:10 +00:00
|
|
|
#include "xfs_format.h"
|
|
|
|
#include "xfs_log_format.h"
|
|
|
|
#include "xfs_trans_resv.h"
|
2005-04-16 22:20:36 +00:00
|
|
|
#include "xfs_mount.h"
|
|
|
|
#include "xfs_inode.h"
|
2013-10-22 23:50:10 +00:00
|
|
|
#include "xfs_trans.h"
|
2005-04-16 22:20:36 +00:00
|
|
|
#include "xfs_iomap.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"
|
2013-08-12 10:49:42 +00:00
|
|
|
#include "xfs_bmap_util.h"
|
2016-10-03 16:11:34 +00:00
|
|
|
#include "xfs_reflink.h"
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2016-02-15 06:21:19 +00:00
|
|
|
struct xfs_writepage_ctx {
|
2019-10-17 20:12:15 +00:00
|
|
|
struct iomap_writepage_ctx ctx;
|
xfs: validate writeback mapping using data fork seq counter
The writeback code caches the current extent mapping across multiple
xfs_do_writepage() calls to avoid repeated lookups for sequential
pages backed by the same extent. This is known to be slightly racy
with extent fork changes in certain difficult to reproduce
scenarios. The cached extent is trimmed to within EOF to help avoid
the most common vector for this problem via speculative
preallocation management, but this is a band-aid that does not
address the fundamental problem.
Now that we have an xfs_ifork sequence counter mechanism used to
facilitate COW writeback, we can use the same mechanism to validate
consistency between the data fork and cached writeback mappings. On
its face, this is somewhat of a big hammer approach because any
change to the data fork invalidates any mapping currently cached by
a writeback in progress regardless of whether the data fork change
overlaps with the range under writeback. In practice, however, the
impact of this approach is minimal in most cases.
First, data fork changes (delayed allocations) caused by sustained
sequential buffered writes are amortized across speculative
preallocations. This means that a cached mapping won't be
invalidated by each buffered write of a common file copy workload,
but rather only on less frequent allocation events. Second, the
extent tree is always entirely in-core so an additional lookup of a
usable extent mostly costs a shared ilock cycle and in-memory tree
lookup. This means that a cached mapping reval is relatively cheap
compared to the I/O itself. Third, spurious invalidations don't
impact ioend construction. This means that even if the same extent
is revalidated multiple times across multiple writepage instances,
we still construct and submit the same size ioend (and bio) if the
blocks are physically contiguous.
Update struct xfs_writepage_ctx with a new field to hold the
sequence number of the data fork associated with the currently
cached mapping. Check the wpc seqno against the data fork when the
mapping is validated and reestablish the mapping whenever the fork
has changed since the mapping was cached. This ensures that
writeback always uses a valid extent mapping and thus prevents lost
writebacks and stale delalloc block problems.
Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
2019-02-01 17:14:23 +00:00
|
|
|
unsigned int data_seq;
|
2018-07-17 23:51:52 +00:00
|
|
|
unsigned int cow_seq;
|
2016-02-15 06:21:19 +00:00
|
|
|
};
|
|
|
|
|
2019-10-17 20:12:15 +00:00
|
|
|
static inline struct xfs_writepage_ctx *
|
|
|
|
XFS_WPC(struct iomap_writepage_ctx *ctx)
|
|
|
|
{
|
|
|
|
return container_of(ctx, struct xfs_writepage_ctx, ctx);
|
|
|
|
}
|
|
|
|
|
2011-08-23 08:28:11 +00:00
|
|
|
/*
|
|
|
|
* Fast and loose check if this write could update the on-disk inode size.
|
|
|
|
*/
|
2019-10-17 20:12:15 +00:00
|
|
|
static inline bool xfs_ioend_is_append(struct iomap_ioend *ioend)
|
2011-08-23 08:28:11 +00:00
|
|
|
{
|
|
|
|
return ioend->io_offset + ioend->io_size >
|
|
|
|
XFS_I(ioend->io_inode)->i_d.di_size;
|
|
|
|
}
|
|
|
|
|
2012-03-13 08:41:05 +00:00
|
|
|
STATIC int
|
|
|
|
xfs_setfilesize_trans_alloc(
|
2019-10-17 20:12:15 +00:00
|
|
|
struct iomap_ioend *ioend)
|
2012-03-13 08:41:05 +00:00
|
|
|
{
|
|
|
|
struct xfs_mount *mp = XFS_I(ioend->io_inode)->i_mount;
|
|
|
|
struct xfs_trans *tp;
|
|
|
|
int error;
|
|
|
|
|
2019-06-29 02:31:38 +00:00
|
|
|
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp);
|
2016-04-05 23:19:55 +00:00
|
|
|
if (error)
|
2012-03-13 08:41:05 +00:00
|
|
|
return error;
|
|
|
|
|
2019-10-17 20:12:09 +00:00
|
|
|
ioend->io_private = tp;
|
2012-03-13 08:41:05 +00:00
|
|
|
|
2012-06-12 14:20:39 +00:00
|
|
|
/*
|
2012-11-28 02:01:00 +00:00
|
|
|
* We may pass freeze protection with a transaction. So tell lockdep
|
2012-06-12 14:20:39 +00:00
|
|
|
* we released it.
|
|
|
|
*/
|
2015-07-19 21:48:20 +00:00
|
|
|
__sb_writers_release(ioend->io_inode->i_sb, SB_FREEZE_FS);
|
2012-03-13 08:41:05 +00:00
|
|
|
/*
|
|
|
|
* We hand off the transaction to the completion thread now, so
|
|
|
|
* clear the flag here.
|
|
|
|
*/
|
2017-05-03 21:53:12 +00:00
|
|
|
current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS);
|
2012-03-13 08:41:05 +00:00
|
|
|
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 03:49:46 +00:00
|
|
|
/*
|
2011-12-18 20:00:12 +00: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 03:49:46 +00:00
|
|
|
*/
|
2012-03-13 08:41:05 +00:00
|
|
|
STATIC int
|
2016-09-19 01:26:41 +00:00
|
|
|
__xfs_setfilesize(
|
2015-02-01 23:02:09 +00:00
|
|
|
struct xfs_inode *ip,
|
|
|
|
struct xfs_trans *tp,
|
|
|
|
xfs_off_t offset,
|
|
|
|
size_t size)
|
[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;
|
|
|
|
|
2012-02-29 09:53:48 +00:00
|
|
|
xfs_ilock(ip, XFS_ILOCK_EXCL);
|
2015-02-01 23:02:09 +00:00
|
|
|
isize = xfs_new_eof(ip, offset + size);
|
2012-03-13 08:41:05 +00:00
|
|
|
if (!isize) {
|
|
|
|
xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
2015-06-04 03:47:56 +00:00
|
|
|
xfs_trans_cancel(tp);
|
2012-03-13 08:41:05 +00:00
|
|
|
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 03:49:46 +00:00
|
|
|
}
|
|
|
|
|
2015-02-01 23:02:09 +00:00
|
|
|
trace_xfs_setfilesize(ip, offset, size);
|
2012-03-13 08:41:05 +00:00
|
|
|
|
|
|
|
ip->i_d.di_size = isize;
|
|
|
|
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
|
|
|
|
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
|
|
|
|
|
2015-06-04 03:48:08 +00:00
|
|
|
return xfs_trans_commit(tp);
|
2010-02-17 05:36:29 +00:00
|
|
|
}
|
|
|
|
|
2016-09-19 01:26:41 +00:00
|
|
|
int
|
|
|
|
xfs_setfilesize(
|
|
|
|
struct xfs_inode *ip,
|
|
|
|
xfs_off_t offset,
|
|
|
|
size_t size)
|
|
|
|
{
|
|
|
|
struct xfs_mount *mp = ip->i_mount;
|
|
|
|
struct xfs_trans *tp;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp);
|
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
|
|
|
|
return __xfs_setfilesize(ip, tp, offset, size);
|
|
|
|
}
|
|
|
|
|
2015-02-01 23:02:09 +00:00
|
|
|
STATIC int
|
|
|
|
xfs_setfilesize_ioend(
|
2019-10-17 20:12:15 +00:00
|
|
|
struct iomap_ioend *ioend,
|
2016-04-05 22:34:30 +00:00
|
|
|
int error)
|
2015-02-01 23:02:09 +00:00
|
|
|
{
|
|
|
|
struct xfs_inode *ip = XFS_I(ioend->io_inode);
|
2019-10-17 20:12:09 +00:00
|
|
|
struct xfs_trans *tp = ioend->io_private;
|
2015-02-01 23:02:09 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The transaction may have been allocated in the I/O submission thread,
|
|
|
|
* thus we need to mark ourselves as being in a transaction manually.
|
|
|
|
* Similarly for freeze protection.
|
|
|
|
*/
|
2017-05-03 21:53:12 +00:00
|
|
|
current_set_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS);
|
2015-07-19 21:48:20 +00:00
|
|
|
__sb_writers_acquired(VFS_I(ip)->i_sb, SB_FREEZE_FS);
|
2015-02-01 23:02:09 +00:00
|
|
|
|
2015-10-12 04:28:39 +00:00
|
|
|
/* we abort the update if there was an IO error */
|
2016-04-05 22:34:30 +00:00
|
|
|
if (error) {
|
2015-10-12 04:28:39 +00:00
|
|
|
xfs_trans_cancel(tp);
|
2016-04-05 22:34:30 +00:00
|
|
|
return error;
|
2015-10-12 04:28:39 +00:00
|
|
|
}
|
|
|
|
|
2016-09-19 01:26:41 +00:00
|
|
|
return __xfs_setfilesize(ip, tp, ioend->io_offset, ioend->io_size);
|
2015-02-01 23:02:09 +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
|
xfs: implement per-inode writeback completion queues
When scheduling writeback of dirty file data in the page cache, XFS uses
IO completion workqueue items to ensure that filesystem metadata only
updates after the write completes successfully. This is essential for
converting unwritten extents to real extents at the right time and
performing COW remappings.
Unfortunately, XFS queues each IO completion work item to an unbounded
workqueue, which means that the kernel can spawn dozens of threads to
try to handle the items quickly. These threads need to take the ILOCK
to update file metadata, which results in heavy ILOCK contention if a
large number of the work items target a single file, which is
inefficient.
Worse yet, the writeback completion threads get stuck waiting for the
ILOCK while holding transaction reservations, which can use up all
available log reservation space. When that happens, metadata updates to
other parts of the filesystem grind to a halt, even if the filesystem
could otherwise have handled it.
Even worse, if one of the things grinding to a halt happens to be a
thread in the middle of a defer-ops finish holding the same ILOCK and
trying to obtain more log reservation having exhausted the permanent
reservation, we now have an ABBA deadlock - writeback completion has a
transaction reserved and wants the ILOCK, and someone else has the ILOCK
and wants a transaction reservation.
Therefore, we create a per-inode writeback io completion queue + work
item. When writeback finishes, it can add the ioend to the per-inode
queue and let the single worker item process that queue. This
dramatically cuts down on the number of kworkers and ILOCK contention in
the system, and seems to have eliminated an occasional deadlock I was
seeing while running generic/476.
Testing with a program that simulates a heavy random-write workload to a
single file demonstrates that the number of kworkers drops from
approximately 120 threads per file to 1, without dramatically changing
write bandwidth or pagecache access latency.
Note that we leave the xfs-conv workqueue's max_active alone because we
still want to be able to run ioend processing for as many inodes as the
system can handle.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
2019-04-15 20:13:20 +00:00
|
|
|
xfs_end_ioend(
|
2019-10-17 20:12:15 +00:00
|
|
|
struct iomap_ioend *ioend)
|
2005-09-02 06:58:49 +00:00
|
|
|
{
|
2016-04-05 22:34:30 +00:00
|
|
|
struct xfs_inode *ip = XFS_I(ioend->io_inode);
|
2017-03-02 23:02:51 +00:00
|
|
|
xfs_off_t offset = ioend->io_offset;
|
|
|
|
size_t size = ioend->io_size;
|
2019-06-29 02:31:38 +00:00
|
|
|
unsigned int nofs_flag;
|
2017-06-03 07:38:06 +00:00
|
|
|
int 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
|
|
|
|
2019-06-29 02:31:38 +00:00
|
|
|
/*
|
|
|
|
* We can allocate memory here while doing writeback on behalf of
|
|
|
|
* memory reclaim. To avoid memory allocation deadlocks set the
|
|
|
|
* task-wide nofs context for the following operations.
|
|
|
|
*/
|
|
|
|
nofs_flag = memalloc_nofs_save();
|
|
|
|
|
2016-02-08 04:00:02 +00:00
|
|
|
/*
|
2017-03-02 23:02:51 +00:00
|
|
|
* Just clean up the in-memory strutures if the fs has been shut down.
|
2016-02-08 04:00:02 +00:00
|
|
|
*/
|
2017-03-02 23:02:51 +00:00
|
|
|
if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
|
2016-04-05 22:34:30 +00:00
|
|
|
error = -EIO;
|
2017-03-02 23:02:51 +00:00
|
|
|
goto done;
|
|
|
|
}
|
2011-08-24 05:59:25 +00:00
|
|
|
|
2016-10-03 16:11:35 +00:00
|
|
|
/*
|
2017-03-02 23:02:51 +00:00
|
|
|
* Clean up any COW blocks on an I/O error.
|
2016-10-03 16:11:35 +00:00
|
|
|
*/
|
2017-06-03 07:38:06 +00:00
|
|
|
error = blk_status_to_errno(ioend->io_bio->bi_status);
|
2017-03-02 23:02:51 +00:00
|
|
|
if (unlikely(error)) {
|
2019-10-17 20:12:10 +00:00
|
|
|
if (ioend->io_flags & IOMAP_F_SHARED)
|
2017-03-02 23:02:51 +00:00
|
|
|
xfs_reflink_cancel_cow_range(ip, offset, size, true);
|
|
|
|
goto done;
|
2016-10-03 16:11:35 +00:00
|
|
|
}
|
|
|
|
|
2009-10-30 09:11:47 +00:00
|
|
|
/*
|
2019-02-15 16:02:46 +00:00
|
|
|
* Success: commit the COW or unwritten blocks if needed.
|
2009-10-30 09:11:47 +00:00
|
|
|
*/
|
2019-10-17 20:12:10 +00:00
|
|
|
if (ioend->io_flags & IOMAP_F_SHARED)
|
2017-03-02 23:02:51 +00:00
|
|
|
error = xfs_reflink_end_cow(ip, offset, size);
|
2019-10-17 20:12:06 +00:00
|
|
|
else if (ioend->io_type == IOMAP_UNWRITTEN)
|
2017-09-21 18:26:18 +00:00
|
|
|
error = xfs_iomap_write_unwritten(ip, offset, size, false);
|
2019-02-15 16:02:46 +00:00
|
|
|
else
|
2019-10-17 20:12:09 +00:00
|
|
|
ASSERT(!xfs_ioend_is_append(ioend) || ioend->io_private);
|
[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
|
|
|
|
2011-08-24 05:59:25 +00:00
|
|
|
done:
|
2019-10-17 20:12:09 +00:00
|
|
|
if (ioend->io_private)
|
2017-03-02 23:02:51 +00:00
|
|
|
error = xfs_setfilesize_ioend(ioend, error);
|
2019-10-17 20:12:15 +00:00
|
|
|
iomap_finish_ioends(ioend, error);
|
2019-06-29 02:31:38 +00:00
|
|
|
memalloc_nofs_restore(nofs_flag);
|
2019-04-15 20:13:21 +00:00
|
|
|
}
|
|
|
|
|
2019-06-29 02:31:37 +00:00
|
|
|
/*
|
|
|
|
* If the to be merged ioend has a preallocated transaction for file
|
|
|
|
* size updates we need to ensure the ioend it is merged into also
|
|
|
|
* has one. If it already has one we can simply cancel the transaction
|
|
|
|
* as it is guaranteed to be clean.
|
|
|
|
*/
|
|
|
|
static void
|
2019-10-17 20:12:09 +00:00
|
|
|
xfs_ioend_merge_private(
|
2019-10-17 20:12:15 +00:00
|
|
|
struct iomap_ioend *ioend,
|
|
|
|
struct iomap_ioend *next)
|
2019-06-29 02:31:37 +00:00
|
|
|
{
|
2019-10-17 20:12:09 +00:00
|
|
|
if (!ioend->io_private) {
|
|
|
|
ioend->io_private = next->io_private;
|
|
|
|
next->io_private = NULL;
|
2019-06-29 02:31:37 +00:00
|
|
|
} else {
|
|
|
|
xfs_setfilesize_ioend(next, -ECANCELED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
xfs: implement per-inode writeback completion queues
When scheduling writeback of dirty file data in the page cache, XFS uses
IO completion workqueue items to ensure that filesystem metadata only
updates after the write completes successfully. This is essential for
converting unwritten extents to real extents at the right time and
performing COW remappings.
Unfortunately, XFS queues each IO completion work item to an unbounded
workqueue, which means that the kernel can spawn dozens of threads to
try to handle the items quickly. These threads need to take the ILOCK
to update file metadata, which results in heavy ILOCK contention if a
large number of the work items target a single file, which is
inefficient.
Worse yet, the writeback completion threads get stuck waiting for the
ILOCK while holding transaction reservations, which can use up all
available log reservation space. When that happens, metadata updates to
other parts of the filesystem grind to a halt, even if the filesystem
could otherwise have handled it.
Even worse, if one of the things grinding to a halt happens to be a
thread in the middle of a defer-ops finish holding the same ILOCK and
trying to obtain more log reservation having exhausted the permanent
reservation, we now have an ABBA deadlock - writeback completion has a
transaction reserved and wants the ILOCK, and someone else has the ILOCK
and wants a transaction reservation.
Therefore, we create a per-inode writeback io completion queue + work
item. When writeback finishes, it can add the ioend to the per-inode
queue and let the single worker item process that queue. This
dramatically cuts down on the number of kworkers and ILOCK contention in
the system, and seems to have eliminated an occasional deadlock I was
seeing while running generic/476.
Testing with a program that simulates a heavy random-write workload to a
single file demonstrates that the number of kworkers drops from
approximately 120 threads per file to 1, without dramatically changing
write bandwidth or pagecache access latency.
Note that we leave the xfs-conv workqueue's max_active alone because we
still want to be able to run ioend processing for as many inodes as the
system can handle.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
2019-04-15 20:13:20 +00:00
|
|
|
/* Finish all pending io completions. */
|
|
|
|
void
|
|
|
|
xfs_end_io(
|
|
|
|
struct work_struct *work)
|
|
|
|
{
|
2019-10-17 20:12:07 +00:00
|
|
|
struct xfs_inode *ip =
|
|
|
|
container_of(work, struct xfs_inode, i_ioend_work);
|
2019-10-17 20:12:15 +00:00
|
|
|
struct iomap_ioend *ioend;
|
2019-10-17 20:12:07 +00:00
|
|
|
struct list_head tmp;
|
xfs: implement per-inode writeback completion queues
When scheduling writeback of dirty file data in the page cache, XFS uses
IO completion workqueue items to ensure that filesystem metadata only
updates after the write completes successfully. This is essential for
converting unwritten extents to real extents at the right time and
performing COW remappings.
Unfortunately, XFS queues each IO completion work item to an unbounded
workqueue, which means that the kernel can spawn dozens of threads to
try to handle the items quickly. These threads need to take the ILOCK
to update file metadata, which results in heavy ILOCK contention if a
large number of the work items target a single file, which is
inefficient.
Worse yet, the writeback completion threads get stuck waiting for the
ILOCK while holding transaction reservations, which can use up all
available log reservation space. When that happens, metadata updates to
other parts of the filesystem grind to a halt, even if the filesystem
could otherwise have handled it.
Even worse, if one of the things grinding to a halt happens to be a
thread in the middle of a defer-ops finish holding the same ILOCK and
trying to obtain more log reservation having exhausted the permanent
reservation, we now have an ABBA deadlock - writeback completion has a
transaction reserved and wants the ILOCK, and someone else has the ILOCK
and wants a transaction reservation.
Therefore, we create a per-inode writeback io completion queue + work
item. When writeback finishes, it can add the ioend to the per-inode
queue and let the single worker item process that queue. This
dramatically cuts down on the number of kworkers and ILOCK contention in
the system, and seems to have eliminated an occasional deadlock I was
seeing while running generic/476.
Testing with a program that simulates a heavy random-write workload to a
single file demonstrates that the number of kworkers drops from
approximately 120 threads per file to 1, without dramatically changing
write bandwidth or pagecache access latency.
Note that we leave the xfs-conv workqueue's max_active alone because we
still want to be able to run ioend processing for as many inodes as the
system can handle.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
2019-04-15 20:13:20 +00:00
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&ip->i_ioend_lock, flags);
|
2019-10-17 20:12:07 +00:00
|
|
|
list_replace_init(&ip->i_ioend_list, &tmp);
|
xfs: implement per-inode writeback completion queues
When scheduling writeback of dirty file data in the page cache, XFS uses
IO completion workqueue items to ensure that filesystem metadata only
updates after the write completes successfully. This is essential for
converting unwritten extents to real extents at the right time and
performing COW remappings.
Unfortunately, XFS queues each IO completion work item to an unbounded
workqueue, which means that the kernel can spawn dozens of threads to
try to handle the items quickly. These threads need to take the ILOCK
to update file metadata, which results in heavy ILOCK contention if a
large number of the work items target a single file, which is
inefficient.
Worse yet, the writeback completion threads get stuck waiting for the
ILOCK while holding transaction reservations, which can use up all
available log reservation space. When that happens, metadata updates to
other parts of the filesystem grind to a halt, even if the filesystem
could otherwise have handled it.
Even worse, if one of the things grinding to a halt happens to be a
thread in the middle of a defer-ops finish holding the same ILOCK and
trying to obtain more log reservation having exhausted the permanent
reservation, we now have an ABBA deadlock - writeback completion has a
transaction reserved and wants the ILOCK, and someone else has the ILOCK
and wants a transaction reservation.
Therefore, we create a per-inode writeback io completion queue + work
item. When writeback finishes, it can add the ioend to the per-inode
queue and let the single worker item process that queue. This
dramatically cuts down on the number of kworkers and ILOCK contention in
the system, and seems to have eliminated an occasional deadlock I was
seeing while running generic/476.
Testing with a program that simulates a heavy random-write workload to a
single file demonstrates that the number of kworkers drops from
approximately 120 threads per file to 1, without dramatically changing
write bandwidth or pagecache access latency.
Note that we leave the xfs-conv workqueue's max_active alone because we
still want to be able to run ioend processing for as many inodes as the
system can handle.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
2019-04-15 20:13:20 +00:00
|
|
|
spin_unlock_irqrestore(&ip->i_ioend_lock, flags);
|
|
|
|
|
2019-10-17 20:12:15 +00:00
|
|
|
iomap_sort_ioends(&tmp);
|
|
|
|
while ((ioend = list_first_entry_or_null(&tmp, struct iomap_ioend,
|
2019-10-17 20:12:07 +00:00
|
|
|
io_list))) {
|
xfs: implement per-inode writeback completion queues
When scheduling writeback of dirty file data in the page cache, XFS uses
IO completion workqueue items to ensure that filesystem metadata only
updates after the write completes successfully. This is essential for
converting unwritten extents to real extents at the right time and
performing COW remappings.
Unfortunately, XFS queues each IO completion work item to an unbounded
workqueue, which means that the kernel can spawn dozens of threads to
try to handle the items quickly. These threads need to take the ILOCK
to update file metadata, which results in heavy ILOCK contention if a
large number of the work items target a single file, which is
inefficient.
Worse yet, the writeback completion threads get stuck waiting for the
ILOCK while holding transaction reservations, which can use up all
available log reservation space. When that happens, metadata updates to
other parts of the filesystem grind to a halt, even if the filesystem
could otherwise have handled it.
Even worse, if one of the things grinding to a halt happens to be a
thread in the middle of a defer-ops finish holding the same ILOCK and
trying to obtain more log reservation having exhausted the permanent
reservation, we now have an ABBA deadlock - writeback completion has a
transaction reserved and wants the ILOCK, and someone else has the ILOCK
and wants a transaction reservation.
Therefore, we create a per-inode writeback io completion queue + work
item. When writeback finishes, it can add the ioend to the per-inode
queue and let the single worker item process that queue. This
dramatically cuts down on the number of kworkers and ILOCK contention in
the system, and seems to have eliminated an occasional deadlock I was
seeing while running generic/476.
Testing with a program that simulates a heavy random-write workload to a
single file demonstrates that the number of kworkers drops from
approximately 120 threads per file to 1, without dramatically changing
write bandwidth or pagecache access latency.
Note that we leave the xfs-conv workqueue's max_active alone because we
still want to be able to run ioend processing for as many inodes as the
system can handle.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
2019-04-15 20:13:20 +00:00
|
|
|
list_del_init(&ioend->io_list);
|
2019-10-17 20:12:15 +00:00
|
|
|
iomap_ioend_try_merge(ioend, &tmp, xfs_ioend_merge_private);
|
xfs: implement per-inode writeback completion queues
When scheduling writeback of dirty file data in the page cache, XFS uses
IO completion workqueue items to ensure that filesystem metadata only
updates after the write completes successfully. This is essential for
converting unwritten extents to real extents at the right time and
performing COW remappings.
Unfortunately, XFS queues each IO completion work item to an unbounded
workqueue, which means that the kernel can spawn dozens of threads to
try to handle the items quickly. These threads need to take the ILOCK
to update file metadata, which results in heavy ILOCK contention if a
large number of the work items target a single file, which is
inefficient.
Worse yet, the writeback completion threads get stuck waiting for the
ILOCK while holding transaction reservations, which can use up all
available log reservation space. When that happens, metadata updates to
other parts of the filesystem grind to a halt, even if the filesystem
could otherwise have handled it.
Even worse, if one of the things grinding to a halt happens to be a
thread in the middle of a defer-ops finish holding the same ILOCK and
trying to obtain more log reservation having exhausted the permanent
reservation, we now have an ABBA deadlock - writeback completion has a
transaction reserved and wants the ILOCK, and someone else has the ILOCK
and wants a transaction reservation.
Therefore, we create a per-inode writeback io completion queue + work
item. When writeback finishes, it can add the ioend to the per-inode
queue and let the single worker item process that queue. This
dramatically cuts down on the number of kworkers and ILOCK contention in
the system, and seems to have eliminated an occasional deadlock I was
seeing while running generic/476.
Testing with a program that simulates a heavy random-write workload to a
single file demonstrates that the number of kworkers drops from
approximately 120 threads per file to 1, without dramatically changing
write bandwidth or pagecache access latency.
Note that we leave the xfs-conv workqueue's max_active alone because we
still want to be able to run ioend processing for as many inodes as the
system can handle.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
2019-04-15 20:13:20 +00:00
|
|
|
xfs_end_ioend(ioend);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-17 20:12:15 +00:00
|
|
|
static inline bool xfs_ioend_needs_workqueue(struct iomap_ioend *ioend)
|
2019-10-17 20:12:10 +00:00
|
|
|
{
|
|
|
|
return ioend->io_private ||
|
|
|
|
ioend->io_type == IOMAP_UNWRITTEN ||
|
|
|
|
(ioend->io_flags & IOMAP_F_SHARED);
|
|
|
|
}
|
|
|
|
|
2016-04-05 22:34:30 +00:00
|
|
|
STATIC void
|
|
|
|
xfs_end_bio(
|
|
|
|
struct bio *bio)
|
2005-09-02 06:58:49 +00:00
|
|
|
{
|
2019-10-17 20:12:15 +00:00
|
|
|
struct iomap_ioend *ioend = bio->bi_private;
|
xfs: implement per-inode writeback completion queues
When scheduling writeback of dirty file data in the page cache, XFS uses
IO completion workqueue items to ensure that filesystem metadata only
updates after the write completes successfully. This is essential for
converting unwritten extents to real extents at the right time and
performing COW remappings.
Unfortunately, XFS queues each IO completion work item to an unbounded
workqueue, which means that the kernel can spawn dozens of threads to
try to handle the items quickly. These threads need to take the ILOCK
to update file metadata, which results in heavy ILOCK contention if a
large number of the work items target a single file, which is
inefficient.
Worse yet, the writeback completion threads get stuck waiting for the
ILOCK while holding transaction reservations, which can use up all
available log reservation space. When that happens, metadata updates to
other parts of the filesystem grind to a halt, even if the filesystem
could otherwise have handled it.
Even worse, if one of the things grinding to a halt happens to be a
thread in the middle of a defer-ops finish holding the same ILOCK and
trying to obtain more log reservation having exhausted the permanent
reservation, we now have an ABBA deadlock - writeback completion has a
transaction reserved and wants the ILOCK, and someone else has the ILOCK
and wants a transaction reservation.
Therefore, we create a per-inode writeback io completion queue + work
item. When writeback finishes, it can add the ioend to the per-inode
queue and let the single worker item process that queue. This
dramatically cuts down on the number of kworkers and ILOCK contention in
the system, and seems to have eliminated an occasional deadlock I was
seeing while running generic/476.
Testing with a program that simulates a heavy random-write workload to a
single file demonstrates that the number of kworkers drops from
approximately 120 threads per file to 1, without dramatically changing
write bandwidth or pagecache access latency.
Note that we leave the xfs-conv workqueue's max_active alone because we
still want to be able to run ioend processing for as many inodes as the
system can handle.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
2019-04-15 20:13:20 +00:00
|
|
|
struct xfs_inode *ip = XFS_I(ioend->io_inode);
|
|
|
|
unsigned long flags;
|
2005-09-02 06:58:49 +00:00
|
|
|
|
2019-10-17 20:12:15 +00:00
|
|
|
ASSERT(xfs_ioend_needs_workqueue(ioend));
|
|
|
|
|
|
|
|
spin_lock_irqsave(&ip->i_ioend_lock, flags);
|
|
|
|
if (list_empty(&ip->i_ioend_list))
|
|
|
|
WARN_ON_ONCE(!queue_work(ip->i_mount->m_unwritten_workqueue,
|
|
|
|
&ip->i_ioend_work));
|
|
|
|
list_add_tail(&ioend->io_list, &ip->i_ioend_list);
|
|
|
|
spin_unlock_irqrestore(&ip->i_ioend_lock, flags);
|
2005-09-02 06:58:49 +00:00
|
|
|
}
|
|
|
|
|
xfs: validate writeback mapping using data fork seq counter
The writeback code caches the current extent mapping across multiple
xfs_do_writepage() calls to avoid repeated lookups for sequential
pages backed by the same extent. This is known to be slightly racy
with extent fork changes in certain difficult to reproduce
scenarios. The cached extent is trimmed to within EOF to help avoid
the most common vector for this problem via speculative
preallocation management, but this is a band-aid that does not
address the fundamental problem.
Now that we have an xfs_ifork sequence counter mechanism used to
facilitate COW writeback, we can use the same mechanism to validate
consistency between the data fork and cached writeback mappings. On
its face, this is somewhat of a big hammer approach because any
change to the data fork invalidates any mapping currently cached by
a writeback in progress regardless of whether the data fork change
overlaps with the range under writeback. In practice, however, the
impact of this approach is minimal in most cases.
First, data fork changes (delayed allocations) caused by sustained
sequential buffered writes are amortized across speculative
preallocations. This means that a cached mapping won't be
invalidated by each buffered write of a common file copy workload,
but rather only on less frequent allocation events. Second, the
extent tree is always entirely in-core so an additional lookup of a
usable extent mostly costs a shared ilock cycle and in-memory tree
lookup. This means that a cached mapping reval is relatively cheap
compared to the I/O itself. Third, spurious invalidations don't
impact ioend construction. This means that even if the same extent
is revalidated multiple times across multiple writepage instances,
we still construct and submit the same size ioend (and bio) if the
blocks are physically contiguous.
Update struct xfs_writepage_ctx with a new field to hold the
sequence number of the data fork associated with the currently
cached mapping. Check the wpc seqno against the data fork when the
mapping is validated and reestablish the mapping whenever the fork
has changed since the mapping was cached. This ensures that
writeback always uses a valid extent mapping and thus prevents lost
writebacks and stale delalloc block problems.
Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
2019-02-01 17:14:23 +00:00
|
|
|
/*
|
|
|
|
* Fast revalidation of the cached writeback mapping. Return true if the current
|
|
|
|
* mapping is valid, false otherwise.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
xfs_imap_valid(
|
2019-10-17 20:12:15 +00:00
|
|
|
struct iomap_writepage_ctx *wpc,
|
xfs: validate writeback mapping using data fork seq counter
The writeback code caches the current extent mapping across multiple
xfs_do_writepage() calls to avoid repeated lookups for sequential
pages backed by the same extent. This is known to be slightly racy
with extent fork changes in certain difficult to reproduce
scenarios. The cached extent is trimmed to within EOF to help avoid
the most common vector for this problem via speculative
preallocation management, but this is a band-aid that does not
address the fundamental problem.
Now that we have an xfs_ifork sequence counter mechanism used to
facilitate COW writeback, we can use the same mechanism to validate
consistency between the data fork and cached writeback mappings. On
its face, this is somewhat of a big hammer approach because any
change to the data fork invalidates any mapping currently cached by
a writeback in progress regardless of whether the data fork change
overlaps with the range under writeback. In practice, however, the
impact of this approach is minimal in most cases.
First, data fork changes (delayed allocations) caused by sustained
sequential buffered writes are amortized across speculative
preallocations. This means that a cached mapping won't be
invalidated by each buffered write of a common file copy workload,
but rather only on less frequent allocation events. Second, the
extent tree is always entirely in-core so an additional lookup of a
usable extent mostly costs a shared ilock cycle and in-memory tree
lookup. This means that a cached mapping reval is relatively cheap
compared to the I/O itself. Third, spurious invalidations don't
impact ioend construction. This means that even if the same extent
is revalidated multiple times across multiple writepage instances,
we still construct and submit the same size ioend (and bio) if the
blocks are physically contiguous.
Update struct xfs_writepage_ctx with a new field to hold the
sequence number of the data fork associated with the currently
cached mapping. Check the wpc seqno against the data fork when the
mapping is validated and reestablish the mapping whenever the fork
has changed since the mapping was cached. This ensures that
writeback always uses a valid extent mapping and thus prevents lost
writebacks and stale delalloc block problems.
Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
2019-02-01 17:14:23 +00:00
|
|
|
struct xfs_inode *ip,
|
2019-10-17 20:12:06 +00:00
|
|
|
loff_t offset)
|
xfs: validate writeback mapping using data fork seq counter
The writeback code caches the current extent mapping across multiple
xfs_do_writepage() calls to avoid repeated lookups for sequential
pages backed by the same extent. This is known to be slightly racy
with extent fork changes in certain difficult to reproduce
scenarios. The cached extent is trimmed to within EOF to help avoid
the most common vector for this problem via speculative
preallocation management, but this is a band-aid that does not
address the fundamental problem.
Now that we have an xfs_ifork sequence counter mechanism used to
facilitate COW writeback, we can use the same mechanism to validate
consistency between the data fork and cached writeback mappings. On
its face, this is somewhat of a big hammer approach because any
change to the data fork invalidates any mapping currently cached by
a writeback in progress regardless of whether the data fork change
overlaps with the range under writeback. In practice, however, the
impact of this approach is minimal in most cases.
First, data fork changes (delayed allocations) caused by sustained
sequential buffered writes are amortized across speculative
preallocations. This means that a cached mapping won't be
invalidated by each buffered write of a common file copy workload,
but rather only on less frequent allocation events. Second, the
extent tree is always entirely in-core so an additional lookup of a
usable extent mostly costs a shared ilock cycle and in-memory tree
lookup. This means that a cached mapping reval is relatively cheap
compared to the I/O itself. Third, spurious invalidations don't
impact ioend construction. This means that even if the same extent
is revalidated multiple times across multiple writepage instances,
we still construct and submit the same size ioend (and bio) if the
blocks are physically contiguous.
Update struct xfs_writepage_ctx with a new field to hold the
sequence number of the data fork associated with the currently
cached mapping. Check the wpc seqno against the data fork when the
mapping is validated and reestablish the mapping whenever the fork
has changed since the mapping was cached. This ensures that
writeback always uses a valid extent mapping and thus prevents lost
writebacks and stale delalloc block problems.
Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
2019-02-01 17:14:23 +00:00
|
|
|
{
|
2019-10-17 20:12:06 +00:00
|
|
|
if (offset < wpc->iomap.offset ||
|
|
|
|
offset >= wpc->iomap.offset + wpc->iomap.length)
|
xfs: validate writeback mapping using data fork seq counter
The writeback code caches the current extent mapping across multiple
xfs_do_writepage() calls to avoid repeated lookups for sequential
pages backed by the same extent. This is known to be slightly racy
with extent fork changes in certain difficult to reproduce
scenarios. The cached extent is trimmed to within EOF to help avoid
the most common vector for this problem via speculative
preallocation management, but this is a band-aid that does not
address the fundamental problem.
Now that we have an xfs_ifork sequence counter mechanism used to
facilitate COW writeback, we can use the same mechanism to validate
consistency between the data fork and cached writeback mappings. On
its face, this is somewhat of a big hammer approach because any
change to the data fork invalidates any mapping currently cached by
a writeback in progress regardless of whether the data fork change
overlaps with the range under writeback. In practice, however, the
impact of this approach is minimal in most cases.
First, data fork changes (delayed allocations) caused by sustained
sequential buffered writes are amortized across speculative
preallocations. This means that a cached mapping won't be
invalidated by each buffered write of a common file copy workload,
but rather only on less frequent allocation events. Second, the
extent tree is always entirely in-core so an additional lookup of a
usable extent mostly costs a shared ilock cycle and in-memory tree
lookup. This means that a cached mapping reval is relatively cheap
compared to the I/O itself. Third, spurious invalidations don't
impact ioend construction. This means that even if the same extent
is revalidated multiple times across multiple writepage instances,
we still construct and submit the same size ioend (and bio) if the
blocks are physically contiguous.
Update struct xfs_writepage_ctx with a new field to hold the
sequence number of the data fork associated with the currently
cached mapping. Check the wpc seqno against the data fork when the
mapping is validated and reestablish the mapping whenever the fork
has changed since the mapping was cached. This ensures that
writeback always uses a valid extent mapping and thus prevents lost
writebacks and stale delalloc block problems.
Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
2019-02-01 17:14:23 +00:00
|
|
|
return false;
|
|
|
|
/*
|
|
|
|
* If this is a COW mapping, it is sufficient to check that the mapping
|
|
|
|
* covers the offset. Be careful to check this first because the caller
|
|
|
|
* can revalidate a COW mapping without updating the data seqno.
|
|
|
|
*/
|
2019-10-17 20:12:10 +00:00
|
|
|
if (wpc->iomap.flags & IOMAP_F_SHARED)
|
xfs: validate writeback mapping using data fork seq counter
The writeback code caches the current extent mapping across multiple
xfs_do_writepage() calls to avoid repeated lookups for sequential
pages backed by the same extent. This is known to be slightly racy
with extent fork changes in certain difficult to reproduce
scenarios. The cached extent is trimmed to within EOF to help avoid
the most common vector for this problem via speculative
preallocation management, but this is a band-aid that does not
address the fundamental problem.
Now that we have an xfs_ifork sequence counter mechanism used to
facilitate COW writeback, we can use the same mechanism to validate
consistency between the data fork and cached writeback mappings. On
its face, this is somewhat of a big hammer approach because any
change to the data fork invalidates any mapping currently cached by
a writeback in progress regardless of whether the data fork change
overlaps with the range under writeback. In practice, however, the
impact of this approach is minimal in most cases.
First, data fork changes (delayed allocations) caused by sustained
sequential buffered writes are amortized across speculative
preallocations. This means that a cached mapping won't be
invalidated by each buffered write of a common file copy workload,
but rather only on less frequent allocation events. Second, the
extent tree is always entirely in-core so an additional lookup of a
usable extent mostly costs a shared ilock cycle and in-memory tree
lookup. This means that a cached mapping reval is relatively cheap
compared to the I/O itself. Third, spurious invalidations don't
impact ioend construction. This means that even if the same extent
is revalidated multiple times across multiple writepage instances,
we still construct and submit the same size ioend (and bio) if the
blocks are physically contiguous.
Update struct xfs_writepage_ctx with a new field to hold the
sequence number of the data fork associated with the currently
cached mapping. Check the wpc seqno against the data fork when the
mapping is validated and reestablish the mapping whenever the fork
has changed since the mapping was cached. This ensures that
writeback always uses a valid extent mapping and thus prevents lost
writebacks and stale delalloc block problems.
Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
2019-02-01 17:14:23 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is not a COW mapping. Check the sequence number of the data fork
|
|
|
|
* because concurrent changes could have invalidated the extent. Check
|
|
|
|
* the COW fork because concurrent changes since the last time we
|
|
|
|
* checked (and found nothing at this offset) could have added
|
|
|
|
* overlapping blocks.
|
|
|
|
*/
|
2019-10-17 20:12:15 +00:00
|
|
|
if (XFS_WPC(wpc)->data_seq != READ_ONCE(ip->i_df.if_seq))
|
xfs: validate writeback mapping using data fork seq counter
The writeback code caches the current extent mapping across multiple
xfs_do_writepage() calls to avoid repeated lookups for sequential
pages backed by the same extent. This is known to be slightly racy
with extent fork changes in certain difficult to reproduce
scenarios. The cached extent is trimmed to within EOF to help avoid
the most common vector for this problem via speculative
preallocation management, but this is a band-aid that does not
address the fundamental problem.
Now that we have an xfs_ifork sequence counter mechanism used to
facilitate COW writeback, we can use the same mechanism to validate
consistency between the data fork and cached writeback mappings. On
its face, this is somewhat of a big hammer approach because any
change to the data fork invalidates any mapping currently cached by
a writeback in progress regardless of whether the data fork change
overlaps with the range under writeback. In practice, however, the
impact of this approach is minimal in most cases.
First, data fork changes (delayed allocations) caused by sustained
sequential buffered writes are amortized across speculative
preallocations. This means that a cached mapping won't be
invalidated by each buffered write of a common file copy workload,
but rather only on less frequent allocation events. Second, the
extent tree is always entirely in-core so an additional lookup of a
usable extent mostly costs a shared ilock cycle and in-memory tree
lookup. This means that a cached mapping reval is relatively cheap
compared to the I/O itself. Third, spurious invalidations don't
impact ioend construction. This means that even if the same extent
is revalidated multiple times across multiple writepage instances,
we still construct and submit the same size ioend (and bio) if the
blocks are physically contiguous.
Update struct xfs_writepage_ctx with a new field to hold the
sequence number of the data fork associated with the currently
cached mapping. Check the wpc seqno against the data fork when the
mapping is validated and reestablish the mapping whenever the fork
has changed since the mapping was cached. This ensures that
writeback always uses a valid extent mapping and thus prevents lost
writebacks and stale delalloc block problems.
Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
2019-02-01 17:14:23 +00:00
|
|
|
return false;
|
|
|
|
if (xfs_inode_has_cow_data(ip) &&
|
2019-10-17 20:12:15 +00:00
|
|
|
XFS_WPC(wpc)->cow_seq != READ_ONCE(ip->i_cowfp->if_seq))
|
xfs: validate writeback mapping using data fork seq counter
The writeback code caches the current extent mapping across multiple
xfs_do_writepage() calls to avoid repeated lookups for sequential
pages backed by the same extent. This is known to be slightly racy
with extent fork changes in certain difficult to reproduce
scenarios. The cached extent is trimmed to within EOF to help avoid
the most common vector for this problem via speculative
preallocation management, but this is a band-aid that does not
address the fundamental problem.
Now that we have an xfs_ifork sequence counter mechanism used to
facilitate COW writeback, we can use the same mechanism to validate
consistency between the data fork and cached writeback mappings. On
its face, this is somewhat of a big hammer approach because any
change to the data fork invalidates any mapping currently cached by
a writeback in progress regardless of whether the data fork change
overlaps with the range under writeback. In practice, however, the
impact of this approach is minimal in most cases.
First, data fork changes (delayed allocations) caused by sustained
sequential buffered writes are amortized across speculative
preallocations. This means that a cached mapping won't be
invalidated by each buffered write of a common file copy workload,
but rather only on less frequent allocation events. Second, the
extent tree is always entirely in-core so an additional lookup of a
usable extent mostly costs a shared ilock cycle and in-memory tree
lookup. This means that a cached mapping reval is relatively cheap
compared to the I/O itself. Third, spurious invalidations don't
impact ioend construction. This means that even if the same extent
is revalidated multiple times across multiple writepage instances,
we still construct and submit the same size ioend (and bio) if the
blocks are physically contiguous.
Update struct xfs_writepage_ctx with a new field to hold the
sequence number of the data fork associated with the currently
cached mapping. Check the wpc seqno against the data fork when the
mapping is validated and reestablish the mapping whenever the fork
has changed since the mapping was cached. This ensures that
writeback always uses a valid extent mapping and thus prevents lost
writebacks and stale delalloc block problems.
Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
2019-02-01 17:14:23 +00:00
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-02-15 16:02:49 +00:00
|
|
|
/*
|
|
|
|
* Pass in a dellalloc extent and convert it to real extents, return the real
|
2019-10-17 20:12:06 +00:00
|
|
|
* extent that maps offset_fsb in wpc->iomap.
|
2019-02-15 16:02:49 +00:00
|
|
|
*
|
|
|
|
* The current page is held locked so nothing could have removed the block
|
2019-02-15 16:02:50 +00:00
|
|
|
* backing offset_fsb, although it could have moved from the COW to the data
|
|
|
|
* fork by another thread.
|
2019-02-15 16:02:49 +00:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
xfs_convert_blocks(
|
2019-10-17 20:12:15 +00:00
|
|
|
struct iomap_writepage_ctx *wpc,
|
2019-02-15 16:02:49 +00:00
|
|
|
struct xfs_inode *ip,
|
2019-10-17 20:12:10 +00:00
|
|
|
int whichfork,
|
2019-10-17 20:12:06 +00:00
|
|
|
loff_t offset)
|
2019-02-15 16:02:49 +00:00
|
|
|
{
|
|
|
|
int error;
|
2019-10-17 20:12:15 +00:00
|
|
|
unsigned *seq;
|
|
|
|
|
|
|
|
if (whichfork == XFS_COW_FORK)
|
|
|
|
seq = &XFS_WPC(wpc)->cow_seq;
|
|
|
|
else
|
|
|
|
seq = &XFS_WPC(wpc)->data_seq;
|
2019-02-15 16:02:49 +00:00
|
|
|
|
|
|
|
/*
|
2019-10-17 20:12:06 +00:00
|
|
|
* Attempt to allocate whatever delalloc extent currently backs offset
|
|
|
|
* and put the result into wpc->iomap. Allocate in a loop because it
|
|
|
|
* may take several attempts to allocate real blocks for a contiguous
|
|
|
|
* delalloc extent if free space is sufficiently fragmented.
|
2019-02-15 16:02:49 +00:00
|
|
|
*/
|
|
|
|
do {
|
2019-10-17 20:12:10 +00:00
|
|
|
error = xfs_bmapi_convert_delalloc(ip, whichfork, offset,
|
2019-10-17 20:12:15 +00:00
|
|
|
&wpc->iomap, seq);
|
2019-02-15 16:02:49 +00:00
|
|
|
if (error)
|
|
|
|
return error;
|
2019-10-17 20:12:06 +00:00
|
|
|
} while (wpc->iomap.offset + wpc->iomap.length <= offset);
|
2019-02-15 16:02:49 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-10-17 20:12:15 +00:00
|
|
|
static int
|
2005-04-16 22:20:36 +00:00
|
|
|
xfs_map_blocks(
|
2019-10-17 20:12:15 +00:00
|
|
|
struct iomap_writepage_ctx *wpc,
|
2005-04-16 22:20:36 +00:00
|
|
|
struct inode *inode,
|
2018-07-12 05:25:59 +00:00
|
|
|
loff_t offset)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2010-12-10 08:42:20 +00:00
|
|
|
struct xfs_inode *ip = XFS_I(inode);
|
|
|
|
struct xfs_mount *mp = ip->i_mount;
|
2017-02-27 22:28:32 +00:00
|
|
|
ssize_t count = i_blocksize(inode);
|
2019-02-15 16:02:47 +00:00
|
|
|
xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset);
|
|
|
|
xfs_fileoff_t end_fsb = XFS_B_TO_FSB(mp, offset + count);
|
2018-07-17 23:51:52 +00:00
|
|
|
xfs_fileoff_t cow_fsb = NULLFILEOFF;
|
2019-10-17 20:12:10 +00:00
|
|
|
int whichfork = XFS_DATA_FORK;
|
2018-07-12 05:25:59 +00:00
|
|
|
struct xfs_bmbt_irec imap;
|
2018-07-12 05:26:01 +00:00
|
|
|
struct xfs_iext_cursor icur;
|
2019-02-15 16:02:50 +00:00
|
|
|
int retries = 0;
|
2010-12-10 08:42:20 +00:00
|
|
|
int error = 0;
|
|
|
|
|
xfs: validate writeback mapping using data fork seq counter
The writeback code caches the current extent mapping across multiple
xfs_do_writepage() calls to avoid repeated lookups for sequential
pages backed by the same extent. This is known to be slightly racy
with extent fork changes in certain difficult to reproduce
scenarios. The cached extent is trimmed to within EOF to help avoid
the most common vector for this problem via speculative
preallocation management, but this is a band-aid that does not
address the fundamental problem.
Now that we have an xfs_ifork sequence counter mechanism used to
facilitate COW writeback, we can use the same mechanism to validate
consistency between the data fork and cached writeback mappings. On
its face, this is somewhat of a big hammer approach because any
change to the data fork invalidates any mapping currently cached by
a writeback in progress regardless of whether the data fork change
overlaps with the range under writeback. In practice, however, the
impact of this approach is minimal in most cases.
First, data fork changes (delayed allocations) caused by sustained
sequential buffered writes are amortized across speculative
preallocations. This means that a cached mapping won't be
invalidated by each buffered write of a common file copy workload,
but rather only on less frequent allocation events. Second, the
extent tree is always entirely in-core so an additional lookup of a
usable extent mostly costs a shared ilock cycle and in-memory tree
lookup. This means that a cached mapping reval is relatively cheap
compared to the I/O itself. Third, spurious invalidations don't
impact ioend construction. This means that even if the same extent
is revalidated multiple times across multiple writepage instances,
we still construct and submit the same size ioend (and bio) if the
blocks are physically contiguous.
Update struct xfs_writepage_ctx with a new field to hold the
sequence number of the data fork associated with the currently
cached mapping. Check the wpc seqno against the data fork when the
mapping is validated and reestablish the mapping whenever the fork
has changed since the mapping was cached. This ensures that
writeback always uses a valid extent mapping and thus prevents lost
writebacks and stale delalloc block problems.
Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
2019-02-01 17:14:23 +00:00
|
|
|
if (XFS_FORCED_SHUTDOWN(mp))
|
|
|
|
return -EIO;
|
|
|
|
|
2018-07-12 05:26:02 +00:00
|
|
|
/*
|
|
|
|
* COW fork blocks can overlap data fork blocks even if the blocks
|
|
|
|
* aren't shared. COW I/O always takes precedent, so we must always
|
|
|
|
* check for overlap on reflink inodes unless the mapping is already a
|
2018-07-17 23:51:52 +00:00
|
|
|
* COW one, or the COW fork hasn't changed from the last time we looked
|
|
|
|
* at it.
|
|
|
|
*
|
|
|
|
* It's safe to check the COW fork if_seq here without the ILOCK because
|
|
|
|
* we've indirectly protected against concurrent updates: writeback has
|
|
|
|
* the page locked, which prevents concurrent invalidations by reflink
|
|
|
|
* and directio and prevents concurrent buffered writes to the same
|
|
|
|
* page. Changes to if_seq always happen under i_lock, which protects
|
|
|
|
* against concurrent updates and provides a memory barrier on the way
|
|
|
|
* out that ensures that we always see the current value.
|
2018-07-12 05:26:02 +00:00
|
|
|
*/
|
2019-10-17 20:12:06 +00:00
|
|
|
if (xfs_imap_valid(wpc, ip, offset))
|
2018-07-12 05:26:02 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we don't have a valid map, now it's time to get a new one for this
|
|
|
|
* offset. This will convert delayed allocations (including COW ones)
|
|
|
|
* into real extents. If we return without a valid map, it means we
|
|
|
|
* landed in a hole and we skip the block.
|
|
|
|
*/
|
2019-02-15 16:02:50 +00:00
|
|
|
retry:
|
2016-02-15 06:20:50 +00:00
|
|
|
xfs_ilock(ip, XFS_ILOCK_SHARED);
|
2010-12-10 08:42:21 +00:00
|
|
|
ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
|
|
|
|
(ip->i_df.if_flags & XFS_IFEXTENTS));
|
2018-07-12 05:26:01 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if this is offset is covered by a COW extents, and if yes use
|
|
|
|
* it directly instead of looking up anything in the data fork.
|
|
|
|
*/
|
2018-07-17 23:51:51 +00:00
|
|
|
if (xfs_inode_has_cow_data(ip) &&
|
2018-07-17 23:51:52 +00:00
|
|
|
xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &icur, &imap))
|
|
|
|
cow_fsb = imap.br_startoff;
|
|
|
|
if (cow_fsb != NULLFILEOFF && cow_fsb <= offset_fsb) {
|
2019-10-17 20:12:15 +00:00
|
|
|
XFS_WPC(wpc)->cow_seq = READ_ONCE(ip->i_cowfp->if_seq);
|
2018-07-12 05:25:59 +00:00
|
|
|
xfs_iunlock(ip, XFS_ILOCK_SHARED);
|
2019-02-15 16:02:46 +00:00
|
|
|
|
2019-10-17 20:12:10 +00:00
|
|
|
whichfork = XFS_COW_FORK;
|
2018-07-12 05:25:59 +00:00
|
|
|
goto allocate_blocks;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
xfs: validate writeback mapping using data fork seq counter
The writeback code caches the current extent mapping across multiple
xfs_do_writepage() calls to avoid repeated lookups for sequential
pages backed by the same extent. This is known to be slightly racy
with extent fork changes in certain difficult to reproduce
scenarios. The cached extent is trimmed to within EOF to help avoid
the most common vector for this problem via speculative
preallocation management, but this is a band-aid that does not
address the fundamental problem.
Now that we have an xfs_ifork sequence counter mechanism used to
facilitate COW writeback, we can use the same mechanism to validate
consistency between the data fork and cached writeback mappings. On
its face, this is somewhat of a big hammer approach because any
change to the data fork invalidates any mapping currently cached by
a writeback in progress regardless of whether the data fork change
overlaps with the range under writeback. In practice, however, the
impact of this approach is minimal in most cases.
First, data fork changes (delayed allocations) caused by sustained
sequential buffered writes are amortized across speculative
preallocations. This means that a cached mapping won't be
invalidated by each buffered write of a common file copy workload,
but rather only on less frequent allocation events. Second, the
extent tree is always entirely in-core so an additional lookup of a
usable extent mostly costs a shared ilock cycle and in-memory tree
lookup. This means that a cached mapping reval is relatively cheap
compared to the I/O itself. Third, spurious invalidations don't
impact ioend construction. This means that even if the same extent
is revalidated multiple times across multiple writepage instances,
we still construct and submit the same size ioend (and bio) if the
blocks are physically contiguous.
Update struct xfs_writepage_ctx with a new field to hold the
sequence number of the data fork associated with the currently
cached mapping. Check the wpc seqno against the data fork when the
mapping is validated and reestablish the mapping whenever the fork
has changed since the mapping was cached. This ensures that
writeback always uses a valid extent mapping and thus prevents lost
writebacks and stale delalloc block problems.
Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
2019-02-01 17:14:23 +00:00
|
|
|
* No COW extent overlap. Revalidate now that we may have updated
|
|
|
|
* ->cow_seq. If the data mapping is still valid, we're done.
|
2018-07-12 05:25:59 +00:00
|
|
|
*/
|
2019-10-17 20:12:06 +00:00
|
|
|
if (xfs_imap_valid(wpc, ip, offset)) {
|
2018-07-12 05:25:59 +00:00
|
|
|
xfs_iunlock(ip, XFS_ILOCK_SHARED);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we don't have a valid map, now it's time to get a new one for this
|
|
|
|
* offset. This will convert delayed allocations (including COW ones)
|
|
|
|
* into real extents.
|
|
|
|
*/
|
2018-07-12 05:26:02 +00:00
|
|
|
if (!xfs_iext_lookup_extent(ip, &ip->i_df, offset_fsb, &icur, &imap))
|
|
|
|
imap.br_startoff = end_fsb; /* fake a hole past EOF */
|
2019-10-17 20:12:15 +00:00
|
|
|
XFS_WPC(wpc)->data_seq = READ_ONCE(ip->i_df.if_seq);
|
2010-12-10 08:42:21 +00:00
|
|
|
xfs_iunlock(ip, XFS_ILOCK_SHARED);
|
2010-12-10 08:42:20 +00:00
|
|
|
|
2019-02-18 17:38:47 +00:00
|
|
|
/* landed in a hole or beyond EOF? */
|
2018-07-12 05:26:02 +00:00
|
|
|
if (imap.br_startoff > offset_fsb) {
|
|
|
|
imap.br_blockcount = imap.br_startoff - offset_fsb;
|
2018-07-12 05:25:59 +00:00
|
|
|
imap.br_startoff = offset_fsb;
|
|
|
|
imap.br_startblock = HOLESTARTBLOCK;
|
2019-02-15 16:02:46 +00:00
|
|
|
imap.br_state = XFS_EXT_NORM;
|
2010-12-10 08:42:21 +00:00
|
|
|
}
|
xfs: make xfs_writepage_map extent map centric
xfs_writepage_map() iterates over the bufferheads on a page to decide
what sort of IO to do and what actions to take. However, when it comes
to reflink and deciding when it needs to execute a COW operation, we no
longer look at the bufferhead state but instead we ignore than and look
up internal state held in the COW fork extent list.
This means xfs_writepage_map() is somewhat confused. It does stuff, then
ignores it, then tries to handle the impedence mismatch by shovelling the
results inside the existing mapping code. It works, but it's a bit of a
mess and it makes it hard to fix the cached map bug that the writepage
code currently has.
To unify the two different mechanisms, we first have to choose a direction.
That's already been set - we're de-emphasising bufferheads so they are no
longer a control structure as we need to do taht to allow for eventual
removal. Hence we need to move away from looking at bufferhead state to
determine what operations we need to perform.
We can't completely get rid of bufferheads yet - they do contain some
state that is absolutely necessary, such as whether that part of the page
contains valid data or not (buffer_uptodate()). Other state in the
bufferhead is redundant:
BH_dirty - the page is dirty, so we can ignore this and just
write it
BH_delay - we have delalloc extent info in the DATA fork extent
tree
BH_unwritten - same as BH_delay
BH_mapped - indicates we've already used it once for IO and it is
mapped to a disk address. Needs to be ignored for COW
blocks.
The BH_mapped flag is an interesting case - it's supposed to indicate that
it's already mapped to disk and so we can just use it "as is". In theory,
we don't even have to do an extent lookup to find where to write it too,
but we have to do that anyway to determine we are actually writing over a
valid extent. Hence it's not even serving the purpose of avoiding a an
extent lookup during writeback, and so we can pretty much ignore it.
Especially as we have to ignore it for COW operations...
Therefore, use the extent map as the source of information to tell us
what actions we need to take and what sort of IO we should perform. The
first step is to have xfs_map_blocks() set the io type according to what
it looks up. This means it can easily handle both normal overwrite and
COW cases. The only thing we also need to add is the ability to return
hole mappings.
We need to return and cache hole mappings now for the case of multiple
blocks per page. We no longer use the BH_mapped to indicate a block over
a hole, so we have to get that info from xfs_map_blocks(). We cache it so
that holes that span two pages don't need separate lookups. This allows us
to avoid ever doing write IO over a hole, too.
Now that we have xfs_map_blocks() returning both a cached map and the type
of IO we need to perform, we can rewrite xfs_writepage_map() to drop all
the bufferhead control. It's also much simplified because it doesn't need
to explicitly handle COW operations. Instead of iterating bufferheads, it
iterates blocks within the page and then looks up what per-block state is
required from the appropriate bufferhead. It then validates the cached
map, and if it's not valid, we get a new map. If we don't get a valid map
or it's over a hole, we skip the block.
At this point, we have to remap the bufferhead via xfs_map_at_offset().
As previously noted, we had to do this even if the buffer was already
mapped as the mapping would be stale for XFS_IO_DELALLOC, XFS_IO_UNWRITTEN
and XFS_IO_COW IO types. With xfs_map_blocks() now controlling the type,
even XFS_IO_OVERWRITE types need remapping, as converted-but-not-yet-
written delalloc extents beyond EOF can be reported at XFS_IO_OVERWRITE.
Bufferheads that span such regions still need their BH_Delay flags cleared
and their block numbers calculated, so we now unconditionally map each
bufferhead before submission.
But wait! There's more - remember the old "treat unwritten extents as
holes on read" hack? Yeah, that means we can have a dirty page with
unmapped, unwritten bufferheads that contain data! What makes these so
special is that the unwritten "hole" bufferheads do not have a valid block
device pointer, so if we attempt to write them xfs_add_to_ioend() blows
up. So we make xfs_map_at_offset() do the "realtime or data device"
lookup from the inode and ignore what was or wasn't put into the
bufferhead when the buffer was instantiated.
The astute reader will have realised by now that this code treats
unwritten extents in multiple-blocks-per-page situations differently.
If we get any combination of unwritten blocks on a dirty page that contain
valid data in the page, we're going to convert them to real extents. This
can actually be a win, because it means that pages with interleaving
unwritten and written blocks will get converted to a single written extent
with zeros replacing the interspersed unwritten blocks. This is actually
good for reducing extent list and conversion overhead, and it means we
issue a contiguous IO instead of lots of little ones. The downside is
that we use up a little extra IO bandwidth. Neither of these seem like a
bad thing given that spinning disks are seek sensitive, and SSDs/pmem have
bandwidth to burn and the lower Io latency/CPU overhead of fewer, larger
IOs will result in better performance on them...
As a result of all this, the only state we actually care about from the
bufferhead is a single flag - BH_Uptodate. We still use the bufferhead to
pass some information to the bio via xfs_add_to_ioend(), but that is
trivial to separate and pass explicitly. This means we really only need
1 bit of state per block per page from the buffered write path in the
writeback path. Everything else we do with the bufferhead is purely to
make the buffered IO front end continue to work correctly. i.e we've
pretty much marginalised bufferheads in the writeback path completely.
Signed-off-By: Dave Chinner <dchinner@redhat.com>
[hch: forward port, refactor and split off bits into other commits]
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
2018-07-12 05:26:00 +00:00
|
|
|
|
2019-02-18 17:38:47 +00:00
|
|
|
/*
|
|
|
|
* Truncate to the next COW extent if there is one. This is the only
|
|
|
|
* opportunity to do this because we can skip COW fork lookups for the
|
|
|
|
* subsequent blocks in the mapping; however, the requirement to treat
|
|
|
|
* the COW range separately remains.
|
|
|
|
*/
|
|
|
|
if (cow_fsb != NULLFILEOFF &&
|
|
|
|
cow_fsb < imap.br_startoff + imap.br_blockcount)
|
|
|
|
imap.br_blockcount = cow_fsb - imap.br_startoff;
|
|
|
|
|
|
|
|
/* got a delalloc extent? */
|
|
|
|
if (imap.br_startblock != HOLESTARTBLOCK &&
|
|
|
|
isnullstartblock(imap.br_startblock))
|
|
|
|
goto allocate_blocks;
|
|
|
|
|
2019-10-17 20:12:06 +00:00
|
|
|
xfs_bmbt_to_iomap(ip, &wpc->iomap, &imap, 0);
|
2019-10-17 20:12:10 +00:00
|
|
|
trace_xfs_map_blocks_found(ip, offset, count, whichfork, &imap);
|
2018-07-12 05:25:59 +00:00
|
|
|
return 0;
|
|
|
|
allocate_blocks:
|
2019-10-17 20:12:10 +00:00
|
|
|
error = xfs_convert_blocks(wpc, ip, whichfork, offset);
|
2019-02-15 16:02:50 +00:00
|
|
|
if (error) {
|
|
|
|
/*
|
|
|
|
* If we failed to find the extent in the COW fork we might have
|
|
|
|
* raced with a COW to data fork conversion or truncate.
|
|
|
|
* Restart the lookup to catch the extent in the data fork for
|
|
|
|
* the former case, but prevent additional retries to avoid
|
|
|
|
* looping forever for the latter case.
|
|
|
|
*/
|
2019-10-17 20:12:10 +00:00
|
|
|
if (error == -EAGAIN && whichfork == XFS_COW_FORK && !retries++)
|
2019-02-15 16:02:50 +00:00
|
|
|
goto retry;
|
|
|
|
ASSERT(error != -EAGAIN);
|
2018-07-12 05:25:59 +00:00
|
|
|
return error;
|
2019-02-15 16:02:50 +00:00
|
|
|
}
|
2019-02-15 16:02:49 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Due to merging the return real extent might be larger than the
|
|
|
|
* original delalloc one. Trim the return extent to the next COW
|
|
|
|
* boundary again to force a re-lookup.
|
|
|
|
*/
|
2019-10-17 20:12:10 +00:00
|
|
|
if (whichfork != XFS_COW_FORK && cow_fsb != NULLFILEOFF) {
|
2019-10-17 20:12:06 +00:00
|
|
|
loff_t cow_offset = XFS_FSB_TO_B(mp, cow_fsb);
|
|
|
|
|
|
|
|
if (cow_offset < wpc->iomap.offset + wpc->iomap.length)
|
|
|
|
wpc->iomap.length = cow_offset - wpc->iomap.offset;
|
|
|
|
}
|
2019-02-15 16:02:49 +00:00
|
|
|
|
2019-10-17 20:12:06 +00:00
|
|
|
ASSERT(wpc->iomap.offset <= offset);
|
|
|
|
ASSERT(wpc->iomap.offset + wpc->iomap.length > offset);
|
2019-10-17 20:12:10 +00:00
|
|
|
trace_xfs_map_blocks_alloc(ip, offset, count, whichfork, &imap);
|
2010-12-10 08:42:21 +00:00
|
|
|
return 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2019-10-17 20:12:15 +00:00
|
|
|
static int
|
|
|
|
xfs_prepare_ioend(
|
|
|
|
struct iomap_ioend *ioend,
|
2016-02-15 06:23:12 +00:00
|
|
|
int status)
|
2006-01-11 04:40:13 +00:00
|
|
|
{
|
2019-06-29 02:31:38 +00:00
|
|
|
unsigned int nofs_flag;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We can allocate memory here while doing writeback on behalf of
|
|
|
|
* memory reclaim. To avoid memory allocation deadlocks set the
|
|
|
|
* task-wide nofs context for the following operations.
|
|
|
|
*/
|
|
|
|
nofs_flag = memalloc_nofs_save();
|
|
|
|
|
2017-02-02 23:14:02 +00:00
|
|
|
/* Convert CoW extents to regular */
|
2019-10-17 20:12:10 +00:00
|
|
|
if (!status && (ioend->io_flags & IOMAP_F_SHARED)) {
|
2017-02-02 23:14:02 +00:00
|
|
|
status = xfs_reflink_convert_cow(XFS_I(ioend->io_inode),
|
|
|
|
ioend->io_offset, ioend->io_size);
|
|
|
|
}
|
|
|
|
|
2016-02-15 06:23:12 +00:00
|
|
|
/* Reserve log space if we might write beyond the on-disk inode size. */
|
|
|
|
if (!status &&
|
2019-10-17 20:12:10 +00:00
|
|
|
((ioend->io_flags & IOMAP_F_SHARED) ||
|
2019-10-17 20:12:06 +00:00
|
|
|
ioend->io_type != IOMAP_UNWRITTEN) &&
|
2016-04-05 22:11:25 +00:00
|
|
|
xfs_ioend_is_append(ioend) &&
|
2019-10-17 20:12:09 +00:00
|
|
|
!ioend->io_private)
|
2016-02-15 06:23:12 +00:00
|
|
|
status = xfs_setfilesize_trans_alloc(ioend);
|
2016-04-05 22:11:25 +00:00
|
|
|
|
2019-06-29 02:31:38 +00:00
|
|
|
memalloc_nofs_restore(nofs_flag);
|
|
|
|
|
2019-10-17 20:12:15 +00:00
|
|
|
if (xfs_ioend_needs_workqueue(ioend))
|
|
|
|
ioend->io_bio->bi_end_io = xfs_end_bio;
|
|
|
|
return status;
|
2006-01-11 04:40:13 +00:00
|
|
|
}
|
|
|
|
|
2010-03-05 02:00:42 +00:00
|
|
|
/*
|
2018-07-12 05:26:05 +00:00
|
|
|
* If the page has delalloc blocks 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 up a later direct I/O read operation on the same region.
|
2010-03-05 02:00:42 +00:00
|
|
|
*
|
2018-07-12 05:26:05 +00:00
|
|
|
* We prevent this by truncating away the delalloc regions on the page. 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).
|
2010-03-05 02:00:42 +00:00
|
|
|
*/
|
2019-10-17 20:12:15 +00:00
|
|
|
static void
|
|
|
|
xfs_discard_page(
|
2010-03-05 02:00:42 +00:00
|
|
|
struct page *page)
|
|
|
|
{
|
|
|
|
struct inode *inode = page->mapping->host;
|
|
|
|
struct xfs_inode *ip = XFS_I(inode);
|
2018-07-12 05:25:57 +00:00
|
|
|
struct xfs_mount *mp = ip->i_mount;
|
2010-03-05 02:00:42 +00:00
|
|
|
loff_t offset = page_offset(page);
|
2018-07-12 05:25:57 +00:00
|
|
|
xfs_fileoff_t start_fsb = XFS_B_TO_FSBT(mp, offset);
|
|
|
|
int error;
|
2010-03-05 02:00:42 +00:00
|
|
|
|
2018-07-12 05:25:57 +00:00
|
|
|
if (XFS_FORCED_SHUTDOWN(mp))
|
2010-03-15 02:36:35 +00:00
|
|
|
goto out_invalidate;
|
|
|
|
|
2020-02-21 15:34:48 +00:00
|
|
|
xfs_alert_ratelimited(mp,
|
2018-01-09 20:02:55 +00:00
|
|
|
"page discard on page "PTR_FMT", inode 0x%llx, offset %llu.",
|
2010-03-05 02:00:42 +00:00
|
|
|
page, ip->i_ino, offset);
|
|
|
|
|
2018-07-12 05:25:57 +00:00
|
|
|
error = xfs_bmap_punch_delalloc_range(ip, start_fsb,
|
|
|
|
PAGE_SIZE / i_blocksize(inode));
|
|
|
|
if (error && !XFS_FORCED_SHUTDOWN(mp))
|
|
|
|
xfs_alert(mp, "page discard unable to remove delalloc mapping.");
|
2010-03-05 02:00:42 +00:00
|
|
|
out_invalidate:
|
2019-10-17 20:12:13 +00:00
|
|
|
iomap_invalidatepage(page, 0, PAGE_SIZE);
|
2010-03-05 02:00:42 +00:00
|
|
|
}
|
|
|
|
|
2019-10-17 20:12:15 +00:00
|
|
|
static const struct iomap_writeback_ops xfs_writeback_ops = {
|
|
|
|
.map_blocks = xfs_map_blocks,
|
|
|
|
.prepare_ioend = xfs_prepare_ioend,
|
|
|
|
.discard_page = xfs_discard_page,
|
|
|
|
};
|
2006-03-14 02:26:27 +00:00
|
|
|
|
2016-02-15 06:21:19 +00:00
|
|
|
STATIC int
|
|
|
|
xfs_vm_writepage(
|
|
|
|
struct page *page,
|
|
|
|
struct writeback_control *wbc)
|
|
|
|
{
|
2019-02-15 16:02:46 +00:00
|
|
|
struct xfs_writepage_ctx wpc = { };
|
2016-02-15 06:21:19 +00:00
|
|
|
|
2019-10-17 20:12:15 +00:00
|
|
|
return iomap_writepage(page, wbc, &wpc.ctx, &xfs_writeback_ops);
|
2016-02-15 06:21:19 +00:00
|
|
|
}
|
|
|
|
|
2006-06-09 05:27:16 +00:00
|
|
|
STATIC int
|
|
|
|
xfs_vm_writepages(
|
|
|
|
struct address_space *mapping,
|
|
|
|
struct writeback_control *wbc)
|
|
|
|
{
|
2019-02-15 16:02:46 +00:00
|
|
|
struct xfs_writepage_ctx wpc = { };
|
2016-02-15 06:21:19 +00:00
|
|
|
|
2007-08-29 01:44:37 +00:00
|
|
|
xfs_iflags_clear(XFS_I(mapping->host), XFS_ITRUNCATED);
|
2019-10-17 20:12:15 +00:00
|
|
|
return iomap_writepages(mapping, wbc, &wpc.ctx, &xfs_writeback_ops);
|
2006-06-09 05:27:16 +00:00
|
|
|
}
|
|
|
|
|
2018-03-07 23:26:44 +00:00
|
|
|
STATIC int
|
|
|
|
xfs_dax_writepages(
|
|
|
|
struct address_space *mapping,
|
|
|
|
struct writeback_control *wbc)
|
|
|
|
{
|
2019-10-25 05:25:38 +00:00
|
|
|
struct xfs_inode *ip = XFS_I(mapping->host);
|
|
|
|
|
|
|
|
xfs_iflags_clear(ip, XFS_ITRUNCATED);
|
2018-03-07 23:26:44 +00:00
|
|
|
return dax_writeback_mapping_range(mapping,
|
2020-01-03 18:33:07 +00:00
|
|
|
xfs_inode_buftarg(ip)->bt_daxdev, wbc);
|
2018-03-07 23:26:44 +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)
|
|
|
|
{
|
2018-06-01 16:03:09 +00:00
|
|
|
struct xfs_inode *ip = XFS_I(mapping->host);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2018-06-01 16:03:09 +00:00
|
|
|
trace_xfs_vm_bmap(ip);
|
2016-10-03 16:11:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The swap code (ab-)uses ->bmap to get a block mapping and then
|
2018-02-28 08:39:48 +00:00
|
|
|
* bypasses the file system for actual I/O. We really can't allow
|
2016-10-03 16:11:36 +00:00
|
|
|
* that on reflinks inodes, so we have to skip out here. And yes,
|
2017-06-22 03:27:35 +00:00
|
|
|
* 0 is the magic code for a bmap error.
|
|
|
|
*
|
|
|
|
* Since we don't pass back blockdev info, we can't return bmap
|
|
|
|
* information for rt files either.
|
2016-10-03 16:11:36 +00:00
|
|
|
*/
|
2019-02-18 17:38:49 +00:00
|
|
|
if (xfs_is_cow_inode(ip) || XFS_IS_REALTIME_INODE(ip))
|
2016-10-03 16:11:36 +00:00
|
|
|
return 0;
|
2019-10-19 16:09:45 +00:00
|
|
|
return iomap_bmap(mapping, block, &xfs_read_iomap_ops);
|
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)
|
|
|
|
{
|
2019-10-19 16:09:45 +00:00
|
|
|
return iomap_readpage(page, &xfs_read_iomap_ops);
|
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)
|
|
|
|
{
|
2019-10-19 16:09:45 +00:00
|
|
|
return iomap_readpages(mapping, pages, nr_pages, &xfs_read_iomap_ops);
|
xfs: don't dirty buffers beyond EOF
generic/263 is failing fsx at this point with a page spanning
EOF that cannot be invalidated. The operations are:
1190 mapwrite 0x52c00 thru 0x5e569 (0xb96a bytes)
1191 mapread 0x5c000 thru 0x5d636 (0x1637 bytes)
1192 write 0x5b600 thru 0x771ff (0x1bc00 bytes)
where 1190 extents EOF from 0x54000 to 0x5e569. When the direct IO
write attempts to invalidate the cached page over this range, it
fails with -EBUSY and so any attempt to do page invalidation fails.
The real question is this: Why can't that page be invalidated after
it has been written to disk and cleaned?
Well, there's data on the first two buffers in the page (1k block
size, 4k page), but the third buffer on the page (i.e. beyond EOF)
is failing drop_buffers because it's bh->b_state == 0x3, which is
BH_Uptodate | BH_Dirty. IOWs, there's dirty buffers beyond EOF. Say
what?
OK, set_buffer_dirty() is called on all buffers from
__set_page_buffers_dirty(), regardless of whether the buffer is
beyond EOF or not, which means that when we get to ->writepage,
we have buffers marked dirty beyond EOF that we need to clean.
So, we need to implement our own .set_page_dirty method that
doesn't dirty buffers beyond EOF.
This is messy because the buffer code is not meant to be shared
and it has interesting locking issues on the buffer dirty bits.
So just copy and paste it and then modify it to suit what we need.
Note: the solutions the other filesystems and generic block code use
of marking the buffers clean in ->writepage does not work for XFS.
It still leaves dirty buffers beyond EOF and invalidations still
fail. Hence rather than play whack-a-mole, this patch simply
prevents those buffers from being dirtied in the first place.
cc: <stable@kernel.org>
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
2014-09-02 02:12:51 +00:00
|
|
|
}
|
|
|
|
|
2018-05-10 15:38:15 +00:00
|
|
|
static int
|
|
|
|
xfs_iomap_swapfile_activate(
|
|
|
|
struct swap_info_struct *sis,
|
|
|
|
struct file *swap_file,
|
|
|
|
sector_t *span)
|
|
|
|
{
|
2019-10-25 05:25:38 +00:00
|
|
|
sis->bdev = xfs_inode_buftarg(XFS_I(file_inode(swap_file)))->bt_bdev;
|
2019-10-19 16:09:45 +00:00
|
|
|
return iomap_swapfile_activate(sis, swap_file, span,
|
|
|
|
&xfs_read_iomap_ops);
|
2018-05-10 15:38:15 +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,
|
2018-07-12 05:26:05 +00:00
|
|
|
.set_page_dirty = iomap_set_page_dirty,
|
2019-10-17 20:12:13 +00:00
|
|
|
.releasepage = iomap_releasepage,
|
|
|
|
.invalidatepage = iomap_invalidatepage,
|
2006-03-14 02:54:26 +00:00
|
|
|
.bmap = xfs_vm_bmap,
|
2018-03-07 23:26:44 +00:00
|
|
|
.direct_IO = noop_direct_IO,
|
2018-07-12 05:26:05 +00:00
|
|
|
.migratepage = iomap_migrate_page,
|
|
|
|
.is_partially_uptodate = iomap_is_partially_uptodate,
|
2009-09-16 09:50:16 +00:00
|
|
|
.error_remove_page = generic_error_remove_page,
|
2018-05-10 15:38:15 +00:00
|
|
|
.swap_activate = xfs_iomap_swapfile_activate,
|
2005-04-16 22:20:36 +00:00
|
|
|
};
|
2018-03-07 23:26:44 +00:00
|
|
|
|
|
|
|
const struct address_space_operations xfs_dax_aops = {
|
|
|
|
.writepages = xfs_dax_writepages,
|
|
|
|
.direct_IO = noop_direct_IO,
|
|
|
|
.set_page_dirty = noop_set_page_dirty,
|
|
|
|
.invalidatepage = noop_invalidatepage,
|
2018-05-10 15:38:15 +00:00
|
|
|
.swap_activate = xfs_iomap_swapfile_activate,
|
2018-03-07 23:26:44 +00:00
|
|
|
};
|