summaryrefslogtreecommitdiff
path: root/fs/xfs/xfs_iomap.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_iomap.c')
-rw-r--r--fs/xfs/xfs_iomap.c115
1 files changed, 71 insertions, 44 deletions
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 00a4b60c97e9..c3c23524a3d2 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -48,14 +48,30 @@ xfs_alert_fsblock_zero(
return -EFSCORRUPTED;
}
+static inline void
+xfs_iomap_sample_seq(
+ const struct iomap_iter *iter,
+ struct xfs_inode *ip)
+{
+ struct xfs_iomap_buffered_ctx *ibc = iter->private;
+
+ if (!ibc)
+ return;
+
+ /* The extent tree sequence is needed for iomap validity checking. */
+ ibc->data_seq = READ_ONCE(ip->i_df.if_seq);
+ ibc->has_cow_seq = xfs_inode_has_cow_data(ip);
+ if (ibc->has_cow_seq)
+ ibc->cow_seq = READ_ONCE(ip->i_cowfp->if_seq);
+}
+
int
xfs_bmbt_to_iomap(
struct xfs_inode *ip,
struct iomap *iomap,
struct xfs_bmbt_irec *imap,
unsigned int mapping_flags,
- u16 iomap_flags,
- int sequence)
+ u16 iomap_flags)
{
struct xfs_mount *mp = ip->i_mount;
struct xfs_buftarg *target = xfs_inode_buftarg(ip);
@@ -92,9 +108,6 @@ xfs_bmbt_to_iomap(
if (xfs_ipincount(ip) &&
(ip->i_itemp->ili_fsync_fields & ~XFS_ILOG_TIMESTAMP))
iomap->flags |= IOMAP_F_DIRTY;
-
- /* The extent tree sequence is needed for iomap validity checking. */
- *((int *)&iomap->private) = sequence;
return 0;
}
@@ -193,14 +206,14 @@ xfs_iomap_eof_align_last_fsb(
return end_fsb;
}
-int
-xfs_iomap_write_direct(
+static int
+__xfs_iomap_write_direct(
struct xfs_inode *ip,
xfs_fileoff_t offset_fsb,
xfs_fileoff_t count_fsb,
unsigned int flags,
struct xfs_bmbt_irec *imap,
- int *seq)
+ const struct iomap_iter *iter)
{
struct xfs_mount *mp = ip->i_mount;
struct xfs_trans *tp;
@@ -290,8 +303,8 @@ xfs_iomap_write_direct(
error = xfs_alert_fsblock_zero(ip, imap);
out_unlock:
- if (seq)
- *seq = READ_ONCE(ip->i_df.if_seq);
+ if (iter)
+ xfs_iomap_sample_seq(iter, ip);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
return error;
@@ -300,6 +313,18 @@ out_trans_cancel:
goto out_unlock;
}
+int
+xfs_iomap_write_direct(
+ struct xfs_inode *ip,
+ xfs_fileoff_t offset_fsb,
+ xfs_fileoff_t count_fsb,
+ unsigned int flags,
+ struct xfs_bmbt_irec *imap)
+{
+ return __xfs_iomap_write_direct(ip, offset_fsb, count_fsb, flags, imap,
+ NULL);
+}
+
STATIC bool
xfs_quota_need_throttle(
struct xfs_inode *ip,
@@ -751,7 +776,6 @@ xfs_direct_write_iomap_begin(
bool shared = false;
u16 iomap_flags = 0;
unsigned int lockmode = XFS_ILOCK_SHARED;
- int seq;
ASSERT(flags & (IOMAP_WRITE | IOMAP_ZERO));
@@ -820,10 +844,10 @@ xfs_direct_write_iomap_begin(
goto out_unlock;
}
- seq = READ_ONCE(ip->i_df.if_seq);
+ xfs_iomap_sample_seq(iter, ip);
xfs_iunlock(ip, lockmode);
trace_xfs_iomap_found(ip, offset, length, XFS_DATA_FORK, &imap);
- return xfs_bmbt_to_iomap(ip, iomap, &imap, flags, iomap_flags, seq);
+ return xfs_bmbt_to_iomap(ip, iomap, &imap, flags, iomap_flags);
allocate_blocks:
error = -EAGAIN;
@@ -848,26 +872,26 @@ allocate_blocks:
end_fsb = min(end_fsb, imap.br_startoff + imap.br_blockcount);
xfs_iunlock(ip, lockmode);
- error = xfs_iomap_write_direct(ip, offset_fsb, end_fsb - offset_fsb,
- flags, &imap, &seq);
+ error = __xfs_iomap_write_direct(ip, offset_fsb, end_fsb - offset_fsb,
+ flags, &imap, iter);
if (error)
return error;
trace_xfs_iomap_alloc(ip, offset, length, XFS_DATA_FORK, &imap);
return xfs_bmbt_to_iomap(ip, iomap, &imap, flags,
- iomap_flags | IOMAP_F_NEW, seq);
+ iomap_flags | IOMAP_F_NEW);
out_found_cow:
- seq = READ_ONCE(ip->i_df.if_seq);
+ xfs_iomap_sample_seq(iter, ip);
xfs_iunlock(ip, lockmode);
length = XFS_FSB_TO_B(mp, cmap.br_startoff + cmap.br_blockcount);
trace_xfs_iomap_found(ip, offset, length - offset, XFS_COW_FORK, &cmap);
if (imap.br_startblock != HOLESTARTBLOCK) {
- error = xfs_bmbt_to_iomap(ip, srcmap, &imap, flags, 0, seq);
+ error = xfs_bmbt_to_iomap(ip, srcmap, &imap, flags, 0);
if (error)
return error;
}
- return xfs_bmbt_to_iomap(ip, iomap, &cmap, flags, IOMAP_F_SHARED, seq);
+ return xfs_bmbt_to_iomap(ip, iomap, &cmap, flags, IOMAP_F_SHARED);
out_unlock:
if (lockmode)
@@ -926,7 +950,6 @@ xfs_buffered_write_iomap_begin(
int allocfork = XFS_DATA_FORK;
int error = 0;
unsigned int lockmode = XFS_ILOCK_EXCL;
- int seq;
if (xfs_is_shutdown(mp))
return -EIO;
@@ -1105,29 +1128,29 @@ retry:
* Flag newly allocated delalloc blocks with IOMAP_F_NEW so we punch
* them out if the write happens to fail.
*/
- seq = READ_ONCE(ip->i_df.if_seq);
+ xfs_iomap_sample_seq(iter, ip);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
trace_xfs_iomap_alloc(ip, offset, count, allocfork, &imap);
- return xfs_bmbt_to_iomap(ip, iomap, &imap, flags, IOMAP_F_NEW, seq);
+ return xfs_bmbt_to_iomap(ip, iomap, &imap, flags, IOMAP_F_NEW);
found_imap:
- seq = READ_ONCE(ip->i_df.if_seq);
+ xfs_iomap_sample_seq(iter, ip);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
- return xfs_bmbt_to_iomap(ip, iomap, &imap, flags, 0, seq);
+ return xfs_bmbt_to_iomap(ip, iomap, &imap, flags, 0);
found_cow:
- seq = READ_ONCE(ip->i_df.if_seq);
+ xfs_iomap_sample_seq(iter, ip);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
if (imap.br_startoff <= offset_fsb) {
- error = xfs_bmbt_to_iomap(ip, srcmap, &imap, flags, 0, seq);
+ error = xfs_bmbt_to_iomap(ip, srcmap, &imap, flags, 0);
if (error)
return error;
return xfs_bmbt_to_iomap(ip, iomap, &cmap, flags,
- IOMAP_F_SHARED, seq);
+ IOMAP_F_SHARED);
}
xfs_trim_extent(&cmap, offset_fsb, imap.br_startoff - offset_fsb);
- return xfs_bmbt_to_iomap(ip, iomap, &cmap, flags, 0, seq);
+ return xfs_bmbt_to_iomap(ip, iomap, &cmap, flags, 0);
out_unlock:
xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -1340,12 +1363,12 @@ xfs_buffered_write_iomap_end(
*/
static bool
xfs_buffered_write_iomap_valid(
- struct inode *inode,
- const struct iomap *iomap)
+ const struct iomap_iter *iter)
{
- int seq = *((int *)&iomap->private);
+ struct xfs_iomap_buffered_ctx *ibc = iter->private;
+ struct xfs_inode *ip = XFS_I(iter->inode);
- if (seq != READ_ONCE(XFS_I(inode)->i_df.if_seq))
+ if (ibc->data_seq != READ_ONCE(ip->i_df.if_seq))
return false;
return true;
}
@@ -1383,7 +1406,6 @@ xfs_read_iomap_begin(
int nimaps = 1, error = 0;
bool shared = false;
unsigned int lockmode = XFS_ILOCK_SHARED;
- int seq;
ASSERT(!(flags & (IOMAP_WRITE | IOMAP_ZERO)));
@@ -1397,14 +1419,15 @@ xfs_read_iomap_begin(
&nimaps, 0);
if (!error && (flags & IOMAP_REPORT))
error = xfs_reflink_trim_around_shared(ip, &imap, &shared);
- seq = READ_ONCE(ip->i_df.if_seq);
+ if (!error)
+ xfs_iomap_sample_seq(iter, ip);
xfs_iunlock(ip, lockmode);
if (error)
return error;
trace_xfs_iomap_found(ip, offset, length, XFS_DATA_FORK, &imap);
return xfs_bmbt_to_iomap(ip, iomap, &imap, flags,
- shared ? IOMAP_F_SHARED : 0, seq);
+ shared ? IOMAP_F_SHARED : 0);
}
const struct iomap_ops xfs_read_iomap_ops = {
@@ -1463,9 +1486,13 @@ xfs_seek_iomap_begin(
if (cow_fsb != NULLFILEOFF && cow_fsb <= offset_fsb) {
if (data_fsb < cow_fsb + cmap.br_blockcount)
end_fsb = min(end_fsb, data_fsb);
+ xfs_iomap_sample_seq(iter, ip);
xfs_trim_extent(&cmap, offset_fsb, end_fsb);
error = xfs_bmbt_to_iomap(ip, iomap, &cmap, flags,
- IOMAP_F_SHARED, READ_ONCE(ip->i_cowfp->if_seq));
+ IOMAP_F_SHARED);
+ if (error)
+ goto out_unlock;
+
/*
* This is a COW extent, so we must probe the page cache
* because there could be dirty page cache being backed
@@ -1487,8 +1514,8 @@ xfs_seek_iomap_begin(
imap.br_state = XFS_EXT_NORM;
done:
xfs_trim_extent(&imap, offset_fsb, end_fsb);
- error = xfs_bmbt_to_iomap(ip, iomap, &imap, flags, 0,
- READ_ONCE(ip->i_df.if_seq));
+ xfs_iomap_sample_seq(iter, ip);
+ error = xfs_bmbt_to_iomap(ip, iomap, &imap, flags, 0);
out_unlock:
xfs_iunlock(ip, lockmode);
return error;
@@ -1515,7 +1542,6 @@ xfs_xattr_iomap_begin(
struct xfs_bmbt_irec imap;
int nimaps = 1, error = 0;
unsigned lockmode;
- int seq;
if (xfs_is_shutdown(mp))
return -EIO;
@@ -1532,14 +1558,13 @@ xfs_xattr_iomap_begin(
error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, &imap,
&nimaps, XFS_BMAPI_ATTRFORK);
out_unlock:
-
- seq = READ_ONCE(ip->i_af.if_seq);
+ xfs_iomap_sample_seq(iter, ip);
xfs_iunlock(ip, lockmode);
if (error)
return error;
ASSERT(nimaps);
- return xfs_bmbt_to_iomap(ip, iomap, &imap, flags, 0, seq);
+ return xfs_bmbt_to_iomap(ip, iomap, &imap, flags, 0);
}
const struct iomap_ops xfs_xattr_iomap_ops = {
@@ -1553,13 +1578,14 @@ xfs_zero_range(
loff_t len,
bool *did_zero)
{
+ struct xfs_iomap_buffered_ctx ibc = { };
struct inode *inode = VFS_I(ip);
if (IS_DAX(inode))
return dax_zero_range(inode, pos, len, did_zero,
&xfs_direct_write_iomap_ops);
return iomap_zero_range(inode, pos, len, did_zero,
- &xfs_buffered_write_iomap_ops, NULL);
+ &xfs_buffered_write_iomap_ops, &ibc);
}
int
@@ -1568,11 +1594,12 @@ xfs_truncate_page(
loff_t pos,
bool *did_zero)
{
+ struct xfs_iomap_buffered_ctx ibc = { };
struct inode *inode = VFS_I(ip);
if (IS_DAX(inode))
return dax_truncate_page(inode, pos, did_zero,
&xfs_direct_write_iomap_ops);
return iomap_truncate_page(inode, pos, did_zero,
- &xfs_buffered_write_iomap_ops, NULL);
+ &xfs_buffered_write_iomap_ops, &ibc);
}