2
0
mirror of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2025-09-04 20:19:47 +08:00

xfs: Fixes for 6.17-rc2

Signed-off-by: Carlos Maiolino <cem@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iJUEABMJAB0WIQSmtYVZ/MfVMGUq1GNcsMJ8RxYuYwUCaJ8nJQAKCRBcsMJ8RxYu
 Y91GAX4q+aKhXBJzzEYGaCGEajMNHlClPI9Ac5AlhSkzW/XdZdS8FhIgJMNegTst
 yOKZ32kBgPoBtiVDbRs7h0USqmcd94f9IwmoLa+0miUKyHHJaZIR97of9F/P1o3q
 Lx2dLf5hwQ==
 =e0dN
 -----END PGP SIGNATURE-----

Merge tag 'xfs-fixes-6.17-rc2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux

Pull xfs fixes from Carlos Maiolino:

 - Fix an assert trigger introduced during the merge window

 - Prevent atomic writes to be used with DAX

 - Prevent users from using the max_atomic_write mount option without
   reflink, as atomic writes > 1block are not supported without reflink

 - Fix a null-pointer-deref in a tracepoint

* tag 'xfs-fixes-6.17-rc2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
  xfs: split xfs_zone_record_blocks
  xfs: fix scrub trace with null pointer in quotacheck
  xfs: reject max_atomic_write mount option for no reflink
  xfs: disallow atomic writes on DAX
  fs/dax: Reject IOCB_ATOMIC in dax_iomap_rw()
  xfs: remove XFS_IBULK_SAME_AG
  xfs: fully decouple XFS_IBULK* flags from XFS_IWALK* flags
  xfs: fix frozen file system assert in xfs_trans_alloc
This commit is contained in:
Linus Torvalds 2025-08-15 12:50:12 -07:00
commit d0efc9e427
12 changed files with 78 additions and 33 deletions

View File

@ -1743,6 +1743,9 @@ dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter,
loff_t done = 0;
int ret;
if (WARN_ON_ONCE(iocb->ki_flags & IOCB_ATOMIC))
return -EIO;
if (!iomi.len)
return 0;

View File

@ -479,7 +479,7 @@ DECLARE_EVENT_CLASS(xchk_dqiter_class,
__field(xfs_exntst_t, state)
),
TP_fast_assign(
__entry->dev = cursor->sc->ip->i_mount->m_super->s_dev;
__entry->dev = cursor->sc->mp->m_super->s_dev;
__entry->dqtype = cursor->dqtype;
__entry->ino = cursor->quota_ip->i_ino;
__entry->cur_id = cursor->id;

View File

@ -1101,9 +1101,6 @@ xfs_file_write_iter(
if (xfs_is_shutdown(ip->i_mount))
return -EIO;
if (IS_DAX(inode))
return xfs_file_dax_write(iocb, from);
if (iocb->ki_flags & IOCB_ATOMIC) {
if (ocount < xfs_get_atomic_write_min(ip))
return -EINVAL;
@ -1116,6 +1113,9 @@ xfs_file_write_iter(
return ret;
}
if (IS_DAX(inode))
return xfs_file_dax_write(iocb, from);
if (iocb->ki_flags & IOCB_DIRECT) {
/*
* Allow a directio write to fall back to a buffered

View File

@ -358,9 +358,20 @@ static inline bool xfs_inode_has_bigrtalloc(const struct xfs_inode *ip)
static inline bool xfs_inode_can_hw_atomic_write(const struct xfs_inode *ip)
{
if (IS_DAX(VFS_IC(ip)))
return false;
return xfs_inode_buftarg(ip)->bt_awu_max > 0;
}
static inline bool xfs_inode_can_sw_atomic_write(const struct xfs_inode *ip)
{
if (IS_DAX(VFS_IC(ip)))
return false;
return xfs_can_sw_atomic_write(ip->i_mount);
}
/*
* In-core inode flags.
*/

View File

@ -219,7 +219,7 @@ xfs_bulk_ireq_setup(
else if (XFS_INO_TO_AGNO(mp, breq->startino) < hdr->agno)
return -EINVAL;
breq->flags |= XFS_IBULK_SAME_AG;
breq->iwalk_flags |= XFS_IWALK_SAME_AG;
/* Asking for an inode past the end of the AG? We're done! */
if (XFS_INO_TO_AGNO(mp, breq->startino) > hdr->agno)

View File

@ -616,7 +616,8 @@ xfs_get_atomic_write_min(
* write of exactly one single fsblock if the bdev will make that
* guarantee for us.
*/
if (xfs_inode_can_hw_atomic_write(ip) || xfs_can_sw_atomic_write(mp))
if (xfs_inode_can_hw_atomic_write(ip) ||
xfs_inode_can_sw_atomic_write(ip))
return mp->m_sb.sb_blocksize;
return 0;
@ -633,7 +634,7 @@ xfs_get_atomic_write_max(
* write of exactly one single fsblock if the bdev will make that
* guarantee for us.
*/
if (!xfs_can_sw_atomic_write(mp)) {
if (!xfs_inode_can_sw_atomic_write(ip)) {
if (xfs_inode_can_hw_atomic_write(ip))
return mp->m_sb.sb_blocksize;
return 0;

View File

@ -307,7 +307,6 @@ xfs_bulkstat(
.breq = breq,
};
struct xfs_trans *tp;
unsigned int iwalk_flags = 0;
int error;
if (breq->idmap != &nop_mnt_idmap) {
@ -328,10 +327,7 @@ xfs_bulkstat(
* locking abilities to detect cycles in the inobt without deadlocking.
*/
tp = xfs_trans_alloc_empty(breq->mp);
if (breq->flags & XFS_IBULK_SAME_AG)
iwalk_flags |= XFS_IWALK_SAME_AG;
error = xfs_iwalk(breq->mp, tp, breq->startino, iwalk_flags,
error = xfs_iwalk(breq->mp, tp, breq->startino, breq->iwalk_flags,
xfs_bulkstat_iwalk, breq->icount, &bc);
xfs_trans_cancel(tp);
kfree(bc.buf);
@ -457,7 +453,7 @@ xfs_inumbers(
* locking abilities to detect cycles in the inobt without deadlocking.
*/
tp = xfs_trans_alloc_empty(breq->mp);
error = xfs_inobt_walk(breq->mp, tp, breq->startino, breq->flags,
error = xfs_inobt_walk(breq->mp, tp, breq->startino, breq->iwalk_flags,
xfs_inumbers_walk, breq->icount, &ic);
xfs_trans_cancel(tp);

View File

@ -13,17 +13,15 @@ struct xfs_ibulk {
xfs_ino_t startino; /* start with this inode */
unsigned int icount; /* number of elements in ubuffer */
unsigned int ocount; /* number of records returned */
unsigned int flags; /* see XFS_IBULK_FLAG_* */
unsigned int flags; /* XFS_IBULK_FLAG_* */
unsigned int iwalk_flags; /* XFS_IWALK_FLAG_* */
};
/* Only iterate within the same AG as startino */
#define XFS_IBULK_SAME_AG (1U << 0)
/* Fill out the bs_extents64 field if set. */
#define XFS_IBULK_NREXT64 (1U << 1)
#define XFS_IBULK_NREXT64 (1U << 0)
/* Signal that we can return metadata directories. */
#define XFS_IBULK_METADIR (1U << 2)
#define XFS_IBULK_METADIR (1U << 1)
/*
* Advance the user buffer pointer by one record of the given size. If the

View File

@ -779,6 +779,25 @@ xfs_set_max_atomic_write_opt(
return -EINVAL;
}
if (xfs_has_reflink(mp))
goto set_limit;
if (new_max_fsbs == 1) {
if (mp->m_ddev_targp->bt_awu_max ||
(mp->m_rtdev_targp && mp->m_rtdev_targp->bt_awu_max)) {
} else {
xfs_warn(mp,
"cannot support atomic writes of size %lluk with no reflink or HW support",
new_max_bytes >> 10);
return -EINVAL;
}
} else {
xfs_warn(mp,
"cannot support atomic writes of size %lluk with no reflink support",
new_max_bytes >> 10);
return -EINVAL;
}
set_limit:
error = xfs_calc_atomic_write_reservation(mp, new_max_fsbs);
if (error) {

View File

@ -455,6 +455,7 @@ DEFINE_EVENT(xfs_zone_alloc_class, name, \
xfs_extlen_t len), \
TP_ARGS(oz, rgbno, len))
DEFINE_ZONE_ALLOC_EVENT(xfs_zone_record_blocks);
DEFINE_ZONE_ALLOC_EVENT(xfs_zone_skip_blocks);
DEFINE_ZONE_ALLOC_EVENT(xfs_zone_alloc_blocks);
TRACE_EVENT(xfs_zone_gc_select_victim,

View File

@ -253,8 +253,8 @@ xfs_trans_alloc(
* by doing GFP_KERNEL allocations inside sb_start_intwrite().
*/
retry:
WARN_ON(mp->m_super->s_writers.frozen == SB_FREEZE_COMPLETE);
tp = __xfs_trans_alloc(mp, flags);
WARN_ON(mp->m_super->s_writers.frozen == SB_FREEZE_COMPLETE);
error = xfs_trans_reserve(tp, resp, blocks, rtextents);
if (error == -ENOSPC && want_retry) {
xfs_trans_cancel(tp);

View File

@ -166,10 +166,9 @@ xfs_open_zone_mark_full(
static void
xfs_zone_record_blocks(
struct xfs_trans *tp,
xfs_fsblock_t fsbno,
xfs_filblks_t len,
struct xfs_open_zone *oz,
bool used)
xfs_fsblock_t fsbno,
xfs_filblks_t len)
{
struct xfs_mount *mp = tp->t_mountp;
struct xfs_rtgroup *rtg = oz->oz_rtg;
@ -179,18 +178,37 @@ xfs_zone_record_blocks(
xfs_rtgroup_lock(rtg, XFS_RTGLOCK_RMAP);
xfs_rtgroup_trans_join(tp, rtg, XFS_RTGLOCK_RMAP);
if (used) {
rmapip->i_used_blocks += len;
ASSERT(rmapip->i_used_blocks <= rtg_blocks(rtg));
} else {
xfs_add_frextents(mp, len);
}
oz->oz_written += len;
if (oz->oz_written == rtg_blocks(rtg))
xfs_open_zone_mark_full(oz);
xfs_trans_log_inode(tp, rmapip, XFS_ILOG_CORE);
}
/*
* Called for blocks that have been written to disk, but not actually linked to
* an inode, which can happen when garbage collection races with user data
* writes to a file.
*/
static void
xfs_zone_skip_blocks(
struct xfs_open_zone *oz,
xfs_filblks_t len)
{
struct xfs_rtgroup *rtg = oz->oz_rtg;
trace_xfs_zone_skip_blocks(oz, 0, len);
xfs_rtgroup_lock(rtg, XFS_RTGLOCK_RMAP);
oz->oz_written += len;
if (oz->oz_written == rtg_blocks(rtg))
xfs_open_zone_mark_full(oz);
xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_RMAP);
xfs_add_frextents(rtg_mount(rtg), len);
}
static int
xfs_zoned_map_extent(
struct xfs_trans *tp,
@ -250,8 +268,7 @@ xfs_zoned_map_extent(
}
}
xfs_zone_record_blocks(tp, new->br_startblock, new->br_blockcount, oz,
true);
xfs_zone_record_blocks(tp, oz, new->br_startblock, new->br_blockcount);
/* Map the new blocks into the data fork. */
xfs_bmap_map_extent(tp, ip, XFS_DATA_FORK, new);
@ -259,8 +276,7 @@ xfs_zoned_map_extent(
skip:
trace_xfs_reflink_cow_remap_skip(ip, new);
xfs_zone_record_blocks(tp, new->br_startblock, new->br_blockcount, oz,
false);
xfs_zone_skip_blocks(oz, new->br_blockcount);
return 0;
}