xfs: fixes for 7.3-rc2

Signed-off-by: Carlos Maiolino <cem@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iJUEABMJAB0WIQSmtYVZ/MfVMGUq1GNcsMJ8RxYuYwUCapUNuQAKCRBcsMJ8RxYu
 Y/QVAX9SDXNSP3dw04wAuYgwSH5Ftm+WAnwusAsSvJkQdTvU0nEpAHyjb6WokS5a
 EbOGy5UBfRyqJFOmOw6wF5Ax0Aoxrt+lN8CuoDoh6aEhtYlh0jvd50ustYX8QSas
 W2R9B6IFIw==
 =JWP4
 -----END PGP SIGNATURE-----

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

Pull xfs fixes from Carlos Maiolino:
 "This contains a few fixes for the zoned storage support, a possible
  deadlock vector fix, some code refactoring patches and a quota evasion
  fix on XFS while exporting it via NFS.

  Please note that for the quota evasion fix, a couple patches for the
  capability subsystem are included in the pull request. Those have been
  ack'ed by the respective maintainer which also agreed to have them
  going through the xfs tree.

  This also includes a patch for the quota subsystem to stop issuing
  audit messages during quota enforcing. Quota maintainer also ack'ed
  and agreed with this going through xfs tree"

* tag 'xfs-fixes-7.3-rc2' of gitolite.kernel.org:/pub/scm/fs/xfs/xfs-linux:
  capability: unexport has_capability_noaudit
  xfs: replace ns_capable_noaudit
  quota: Don't issue audit messages on quota enforcing
  capability: Add new capable_noaudit
  xfs: fix capability check in xfs
  xfs: restore bi_bdev in xfs_zone_gc_write_chunk
  xfs: split ioend handling into a separate source file
  xfs: factor out a xfs_iomap_set_anon_write helper
  xfs: fix zoned write iomap flags assignments
  xfs: fix racy open zone caching
  xfs: handle NULL open_zone for merged ioends in xfs_ioend_put_open_zones
  xfs: use inode_init_always_gfp with __GFP_NOFAIL in xfs_inode_alloc
  xfs: remove kmem_to_page()
  xfs: don't flush and invalidate internal RT device twice in xfs_shutdown_devices
  xfs: split an assert in xfs_trans_log_buf
  xfs: don't hold buffer locks across sync transaction commit in xfs_sync_sb_buf
This commit is contained in:
Linus Torvalds 2026-08-31 10:45:40 -07:00
commit a7f25dc23f
22 changed files with 339 additions and 259 deletions

View File

@ -1240,7 +1240,7 @@ static int ignore_hardlimit(struct dquot *dquot)
{
struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type];
return capable(CAP_SYS_RESOURCE) &&
return capable_noaudit(CAP_SYS_RESOURCE) &&
(info->dqi_format->qf_fmt_id != QFMT_VFS_OLD ||
!(info->dqi_flags & DQF_ROOT_SQUASH));
}

View File

@ -91,6 +91,7 @@ xfs-y += xfs_aops.o \
xfs_healthmon.o \
xfs_icache.o \
xfs_ioctl.o \
xfs_ioend.o \
xfs_iomap.o \
xfs_iops.o \
xfs_inode.o \

View File

@ -359,7 +359,11 @@ static inline int xfs_initialize_rtgroups(struct xfs_mount *mp,
# define xfs_rtgroup_unlock(rtg, gf) ((void)0)
# define xfs_rtgroup_trans_join(tp, rtg, gf) ((void)0)
# define xfs_update_rtsb(bp, sb_bp) ((void)0)
# define xfs_log_rtsb(tp, sb_bp) (NULL)
static inline struct xfs_buf *xfs_log_rtsb(struct xfs_trans *tp,
const struct xfs_buf *sb_bp)
{
return NULL;
}
# define xfs_rtgroup_get_geometry(rtg, rgeo) (-EOPNOTSUPP)
#endif /* CONFIG_XFS_RT */

View File

@ -1470,36 +1470,33 @@ xfs_sync_sb_buf(
bool update_rtsb)
{
struct xfs_trans *tp;
struct xfs_buf *bp;
struct xfs_buf *rtsb_bp = NULL;
int error;
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_sb, 0, 0, 0, &tp);
if (error)
return error;
bp = xfs_trans_getsb(tp);
xfs_log_sb(tp);
xfs_trans_bhold(tp, bp);
if (update_rtsb) {
rtsb_bp = xfs_log_rtsb(tp, bp);
if (rtsb_bp)
xfs_trans_bhold(tp, rtsb_bp);
}
if (update_rtsb)
xfs_log_rtsb(tp, xfs_trans_getsb(tp));
xfs_trans_set_sync(tp);
error = xfs_trans_commit(tp);
if (error)
goto out;
/*
* write out the sb buffer to get the changes to disk
*/
error = xfs_bwrite(bp);
if (!error && rtsb_bp)
error = xfs_bwrite(rtsb_bp);
out:
if (rtsb_bp)
xfs_buf_relse(rtsb_bp);
xfs_buf_relse(bp);
return error;
/* Re-acquire and write the sb and rtsb to disk. */
xfs_buf_lock(mp->m_sb_bp);
error = xfs_bwrite(mp->m_sb_bp);
xfs_buf_unlock(mp->m_sb_bp);
if (error)
return error;
if (update_rtsb && mp->m_rtsb_bp) {
xfs_buf_lock(mp->m_rtsb_bp);
error = xfs_bwrite(mp->m_rtsb_bp);
xfs_buf_unlock(mp->m_rtsb_bp);
}
return error;
}

View File

@ -20,6 +20,7 @@
#include "xfs_errortag.h"
#include "xfs_error.h"
#include "xfs_icache.h"
#include "xfs_ioend.h"
#include "xfs_zone_alloc.h"
#include "xfs_rtgroup.h"
#include <linux/bio-integrity.h>
@ -36,15 +37,6 @@ XFS_WPC(struct iomap_writepage_ctx *ctx)
return container_of(ctx, struct xfs_writepage_ctx, ctx);
}
/*
* Fast and loose check if this write could update the on-disk inode size.
*/
static inline bool xfs_ioend_is_append(struct iomap_ioend *ioend)
{
return ioend->io_offset + ioend->io_size >
XFS_I(ioend->io_inode)->i_disk_size;
}
/*
* Update on-disk file size now that data has been written to disk.
*/
@ -80,175 +72,6 @@ xfs_setfilesize(
return xfs_trans_commit(tp);
}
static void
xfs_ioend_put_open_zones(
struct iomap_ioend *ioend)
{
struct iomap_ioend *tmp;
/*
* Put the open zone for all ioends merged into this one (if any).
*/
list_for_each_entry(tmp, &ioend->io_list, io_list)
xfs_open_zone_put(tmp->io_private);
/*
* The main ioend might not have an open zone if the submission failed
* before xfs_zone_alloc_and_submit got called.
*/
if (ioend->io_private)
xfs_open_zone_put(ioend->io_private);
}
/*
* IO write completion.
*/
STATIC void
xfs_end_ioend_write(
struct iomap_ioend *ioend)
{
struct xfs_inode *ip = XFS_I(ioend->io_inode);
struct xfs_mount *mp = ip->i_mount;
bool is_zoned = xfs_is_zoned_inode(ip);
xfs_off_t offset = ioend->io_offset;
size_t size = ioend->io_size;
unsigned int nofs_flag;
int error;
/*
* 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();
/*
* Just clean up the in-memory structures if the fs has been shut down.
*/
if (xfs_is_shutdown(mp)) {
error = -EIO;
goto done;
}
/*
* Clean up all COW blocks and underlying data fork delalloc blocks on
* I/O error. The delalloc punch is required because this ioend was
* mapped to blocks in the COW fork and the associated pages are no
* longer dirty. If we don't remove delalloc blocks here, they become
* stale and can corrupt free space accounting on unmount.
*/
error = blk_status_to_errno(ioend->io_bio.bi_status);
if (unlikely(error)) {
/*
* Zoned writes update the in-core open zone accounting before
* I/O submission. A failed write leaves that state
* inconsistent, so shut down the filesystem instead of letting
* later writers wait forever for open zone space to become
* available.
*/
if (is_zoned) {
xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
goto done;
}
if (ioend->io_flags & IOMAP_IOEND_SHARED) {
ASSERT(!is_zoned);
xfs_reflink_cancel_cow_range(ip, offset, size, true);
xfs_bmap_punch_delalloc_range(ip, XFS_DATA_FORK, offset,
offset + size, NULL);
}
goto done;
}
/*
* Success: commit the COW or unwritten blocks if needed.
*/
if (is_zoned)
error = xfs_zoned_end_io(ip, offset, size, ioend->io_sector,
ioend->io_private, NULLFSBLOCK);
else if (ioend->io_flags & IOMAP_IOEND_SHARED)
error = xfs_reflink_end_cow(ip, offset, size);
else if (ioend->io_flags & IOMAP_IOEND_UNWRITTEN)
error = xfs_iomap_write_unwritten(ip, offset, size, false);
if (!error &&
!(ioend->io_flags & IOMAP_IOEND_DIRECT) &&
xfs_ioend_is_append(ioend))
error = xfs_setfilesize(ip, offset, size);
done:
if (is_zoned)
xfs_ioend_put_open_zones(ioend);
iomap_finish_ioends(ioend, error);
memalloc_nofs_restore(nofs_flag);
}
/*
* Finish all pending IO completions that require transactional modifications.
*
* We try to merge physical and logically contiguous ioends before completion to
* minimise the number of transactions we need to perform during IO completion.
* Both unwritten extent conversion and COW remapping need to iterate and modify
* one physical extent at a time, so we gain nothing by merging physically
* discontiguous extents here.
*
* The ioend chain length that we can be processing here is largely unbound in
* length and we may have to perform significant amounts of work on each ioend
* to complete it. Hence we have to be careful about holding the CPU for too
* long in this loop.
*/
void
xfs_end_io(
struct work_struct *work)
{
struct xfs_inode *ip =
container_of(work, struct xfs_inode, i_ioend_work);
struct iomap_ioend *ioend;
struct list_head tmp;
unsigned long flags;
spin_lock_irqsave(&ip->i_ioend_lock, flags);
list_replace_init(&ip->i_ioend_list, &tmp);
spin_unlock_irqrestore(&ip->i_ioend_lock, flags);
iomap_sort_ioends(&tmp);
while ((ioend = list_first_entry_or_null(&tmp, struct iomap_ioend,
io_list))) {
list_del_init(&ioend->io_list);
iomap_ioend_try_merge(ioend, &tmp);
if (bio_op(&ioend->io_bio) == REQ_OP_READ)
iomap_finish_ioends(ioend,
blk_status_to_errno(ioend->io_bio.bi_status));
else
xfs_end_ioend_write(ioend);
cond_resched();
}
}
void
xfs_end_bio(
struct bio *bio)
{
struct iomap_ioend *ioend = iomap_ioend_from_bio(bio);
struct xfs_inode *ip = XFS_I(ioend->io_inode);
struct xfs_mount *mp = ip->i_mount;
unsigned long flags;
/*
* For Appends record the actually written block number and set the
* boundary flag if needed.
*/
if (IS_ENABLED(CONFIG_XFS_RT) && bio_is_zone_append(bio)) {
ioend->io_sector = bio->bi_iter.bi_sector;
xfs_mark_rtg_boundary(ioend);
}
spin_lock_irqsave(&ip->i_ioend_lock, flags);
if (list_empty(&ip->i_ioend_list))
WARN_ON_ONCE(!queue_work(mp->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);
}
/*
* We cannot cancel the ioend directly on error. We may have already set other
* pages under writeback and hence we have to run I/O completion to mark the
@ -631,13 +454,8 @@ xfs_zoned_map_blocks(
XFS_BMAPI_REMAP);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
wpc->iomap.type = IOMAP_MAPPED;
wpc->iomap.flags = IOMAP_F_DIRTY;
wpc->iomap.bdev = mp->m_rtdev_targp->bt_bdev;
wpc->iomap.offset = offset;
wpc->iomap.length = XFS_FSB_TO_B(mp, count_fsb);
wpc->iomap.flags = IOMAP_F_ANON_WRITE;
xfs_iomap_set_anon_write(ip, &wpc->iomap, offset,
XFS_FSB_TO_B(mp, count_fsb));
trace_xfs_zoned_map_blocks(ip, offset, wpc->iomap.length);
return 0;
}

View File

@ -10,6 +10,5 @@ extern const struct address_space_operations xfs_address_space_operations;
extern const struct address_space_operations xfs_dax_aops;
int xfs_setfilesize(struct xfs_inode *ip, xfs_off_t offset, size_t size);
void xfs_end_bio(struct bio *bio);
#endif /* __XFS_AOPS_H__ */

View File

@ -25,7 +25,7 @@
#include "xfs_iomap.h"
#include "xfs_reflink.h"
#include "xfs_file.h"
#include "xfs_aops.h"
#include "xfs_ioend.h"
#include "xfs_zone_alloc.h"
#include "xfs_error.h"
#include "xfs_errortag.h"

View File

@ -1174,8 +1174,7 @@ xfs_getfsmap(
if (!xfs_getfsmap_check_keys(&head->fmh_keys[0], &head->fmh_keys[1]))
return -EINVAL;
use_rmap = xfs_has_rmapbt(mp) &&
has_capability_noaudit(current, CAP_SYS_ADMIN);
use_rmap = xfs_has_rmapbt(mp) && capable_noaudit(CAP_SYS_ADMIN);
head->fmh_entries = 0;
/* Set up our device handlers. */

View File

@ -82,24 +82,20 @@ static inline xa_mark_t ici_tag_to_mark(unsigned int tag)
/*
* Allocate and initialise an xfs_inode.
*
* This can happen in context of already dirtied transactions, so the memory
* allocations must not fail.
*/
struct xfs_inode *
xfs_inode_alloc(
struct xfs_mount *mp,
xfs_ino_t ino)
{
gfp_t gfp = GFP_KERNEL | __GFP_NOFAIL;
struct xfs_inode *ip;
/*
* XXX: If this didn't occur in transactions, we could drop GFP_NOFAIL
* and return NULL here on ENOMEM.
*/
ip = alloc_inode_sb(mp->m_super, xfs_inode_cache, GFP_KERNEL | __GFP_NOFAIL);
if (inode_init_always(mp->m_super, VFS_I(ip))) {
kmem_cache_free(xfs_inode_cache, ip);
return NULL;
}
ip = alloc_inode_sb(mp->m_super, xfs_inode_cache, gfp);
inode_init_always_gfp(mp->m_super, VFS_I(ip), gfp);
VFS_I(ip)->i_ino = ino;
/* VFS doesn't initialise i_mode! */

View File

@ -647,7 +647,7 @@ xfs_ioctl_setattr_get_trans(
goto out_error;
error = xfs_trans_alloc_ichange(ip, NULL, NULL, pdqp,
has_capability_noaudit(current, CAP_FOWNER), &tp);
capable_noaudit(CAP_FOWNER), &tp);
if (error)
goto out_error;

184
fs/xfs/xfs_ioend.c Normal file
View File

@ -0,0 +1,184 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016-2025 Christoph Hellwig.
* All Rights Reserved.
*/
#include "xfs_platform.h"
#include "xfs_shared.h"
#include "xfs_format.h"
#include "xfs_log_format.h"
#include "xfs_trans_resv.h"
#include "xfs_mount.h"
#include "xfs_inode.h"
#include "xfs_iomap.h"
#include "xfs_trace.h"
#include "xfs_bmap_util.h"
#include "xfs_reflink.h"
#include "xfs_zone_alloc.h"
#include "xfs_ioend.h"
static void
xfs_ioend_put_open_zones(
struct iomap_ioend *ioend)
{
struct iomap_ioend *tmp;
/*
* Put the open zone for all ioends merged into this one (if any).
*/
list_for_each_entry(tmp, &ioend->io_list, io_list)
xfs_open_zone_put(tmp->io_private);
/*
* The main ioend might not have an open zone if the submission failed
* before xfs_zone_alloc_and_submit got called.
*/
if (ioend->io_private)
xfs_open_zone_put(ioend->io_private);
}
static void
xfs_end_ioend_write(
struct iomap_ioend *ioend)
{
struct xfs_inode *ip = XFS_I(ioend->io_inode);
struct xfs_mount *mp = ip->i_mount;
bool is_zoned = xfs_is_zoned_inode(ip);
xfs_off_t offset = ioend->io_offset;
size_t size = ioend->io_size;
unsigned int nofs_flag;
int error;
/*
* 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();
/*
* Just clean up the in-memory structures if the fs has been shut down.
*/
if (xfs_is_shutdown(mp)) {
error = -EIO;
goto done;
}
/*
* Clean up all COW blocks and underlying data fork delalloc blocks on
* I/O error. The delalloc punch is required because this ioend was
* mapped to blocks in the COW fork and the associated pages are no
* longer dirty. If we don't remove delalloc blocks here, they become
* stale and can corrupt free space accounting on unmount.
*/
error = blk_status_to_errno(ioend->io_bio.bi_status);
if (unlikely(error)) {
/*
* Zoned writes update the in-core open zone accounting before
* I/O submission. A failed write leaves that state
* inconsistent, so shut down the filesystem instead of letting
* later writers wait forever for open zone space to become
* available.
*/
if (is_zoned) {
xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
goto done;
}
if (ioend->io_flags & IOMAP_IOEND_SHARED) {
ASSERT(!is_zoned);
xfs_reflink_cancel_cow_range(ip, offset, size, true);
xfs_bmap_punch_delalloc_range(ip, XFS_DATA_FORK, offset,
offset + size, NULL);
}
goto done;
}
/*
* Success: commit the COW or unwritten blocks if needed.
*/
if (is_zoned)
error = xfs_zoned_end_io(ip, offset, size, ioend->io_sector,
ioend->io_private, NULLFSBLOCK);
else if (ioend->io_flags & IOMAP_IOEND_SHARED)
error = xfs_reflink_end_cow(ip, offset, size);
else if (ioend->io_flags & IOMAP_IOEND_UNWRITTEN)
error = xfs_iomap_write_unwritten(ip, offset, size, false);
if (!error &&
!(ioend->io_flags & IOMAP_IOEND_DIRECT) &&
xfs_ioend_is_append(ioend))
error = xfs_setfilesize(ip, offset, size);
done:
if (is_zoned)
xfs_ioend_put_open_zones(ioend);
iomap_finish_ioends(ioend, error);
memalloc_nofs_restore(nofs_flag);
}
/*
* Finish all pending IO completions that require transactional modifications.
*
* We try to merge physical and logically contiguous ioends before completion to
* minimise the number of transactions we need to perform during IO completion.
* Both unwritten extent conversion and COW remapping need to iterate and modify
* one physical extent at a time, so we gain nothing by merging physically
* discontiguous extents here.
*
* The ioend chain length that we can be processing here is largely unbound in
* length and we may have to perform significant amounts of work on each ioend
* to complete it. Hence we have to be careful about holding the CPU for too
* long in this loop.
*/
void
xfs_end_io(
struct work_struct *work)
{
struct xfs_inode *ip =
container_of(work, struct xfs_inode, i_ioend_work);
struct iomap_ioend *ioend;
struct list_head tmp;
unsigned long flags;
spin_lock_irqsave(&ip->i_ioend_lock, flags);
list_replace_init(&ip->i_ioend_list, &tmp);
spin_unlock_irqrestore(&ip->i_ioend_lock, flags);
iomap_sort_ioends(&tmp);
while ((ioend = list_first_entry_or_null(&tmp, struct iomap_ioend,
io_list))) {
list_del_init(&ioend->io_list);
iomap_ioend_try_merge(ioend, &tmp);
if (bio_op(&ioend->io_bio) == REQ_OP_READ)
iomap_finish_ioends(ioend,
blk_status_to_errno(ioend->io_bio.bi_status));
else
xfs_end_ioend_write(ioend);
cond_resched();
}
}
void
xfs_end_bio(
struct bio *bio)
{
struct iomap_ioend *ioend = iomap_ioend_from_bio(bio);
struct xfs_inode *ip = XFS_I(ioend->io_inode);
struct xfs_mount *mp = ip->i_mount;
unsigned long flags;
/*
* For Appends record the actually written block number and set the
* boundary flag if needed.
*/
if (IS_ENABLED(CONFIG_XFS_RT) && bio_is_zone_append(bio)) {
ioend->io_sector = bio->bi_iter.bi_sector;
xfs_mark_rtg_boundary(ioend);
}
spin_lock_irqsave(&ip->i_ioend_lock, flags);
if (list_empty(&ip->i_ioend_list))
WARN_ON_ONCE(!queue_work(mp->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);
}

16
fs/xfs/xfs_ioend.h Normal file
View File

@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __XFS_IOEND_H
#define __XFS_IOEND_H
/*
* Fast and loose check if this write could update the on-disk inode size.
*/
static inline bool xfs_ioend_is_append(struct iomap_ioend *ioend)
{
return ioend->io_offset + ioend->io_size >
XFS_I(ioend->io_inode)->i_disk_size;
}
void xfs_end_bio(struct bio *bio);
#endif /* __XFS_IOEND_H */

View File

@ -1083,12 +1083,7 @@ xfs_zoned_direct_write_iomap_begin(
return error;
}
iomap->type = IOMAP_MAPPED;
iomap->flags = IOMAP_F_DIRTY;
iomap->bdev = ip->i_mount->m_rtdev_targp->bt_bdev;
iomap->offset = offset;
iomap->length = length;
iomap->flags = IOMAP_F_ANON_WRITE;
xfs_iomap_set_anon_write(ip, iomap, offset, length);
return 0;
}

View File

@ -29,6 +29,20 @@ int xfs_zero_range(struct xfs_inode *ip, loff_t pos, loff_t len,
int xfs_truncate_page(struct xfs_inode *ip, loff_t pos,
struct xfs_zone_alloc_ctx *ac, bool *did_zero);
static inline void
xfs_iomap_set_anon_write(
struct xfs_inode *ip,
struct iomap *iomap,
loff_t offset,
loff_t length)
{
iomap->type = IOMAP_MAPPED;
iomap->bdev = ip->i_mount->m_rtdev_targp->bt_bdev;
iomap->offset = offset;
iomap->length = length;
iomap->flags = IOMAP_F_ANON_WRITE | IOMAP_F_DIRTY;
}
static inline xfs_filblks_t
xfs_aligned_fsb_count(
xfs_fileoff_t offset_fsb,

View File

@ -834,7 +834,7 @@ xfs_setattr_nonsize(
}
error = xfs_trans_alloc_ichange(ip, udqp, gdqp, NULL,
has_capability_noaudit(current, CAP_FOWNER), &tp);
capable_noaudit(CAP_FOWNER), &tp);
if (error)
goto out_dqrele;

View File

@ -289,15 +289,4 @@ int xfs_rw_bdev(struct block_device *bdev, sector_t sector, unsigned int count,
# define PTR_FMT "%p"
#endif
/*
* Helper for IO routines to grab backing pages from allocated kernel memory.
*/
static inline struct page *
kmem_to_page(void *addr)
{
if (is_vmalloc_addr(addr))
return vmalloc_to_page(addr);
return virt_to_page(addr);
}
#endif /* _XFS_PLATFORM_H */

View File

@ -445,7 +445,7 @@ xfs_shutdown_devices(
blkdev_issue_flush(mp->m_logdev_targp->bt_bdev);
invalidate_bdev(mp->m_logdev_targp->bt_bdev);
}
if (mp->m_rtdev_targp) {
if (mp->m_rtdev_targp && mp->m_rtdev_targp != mp->m_ddev_targp) {
blkdev_issue_flush(mp->m_rtdev_targp->bt_bdev);
invalidate_bdev(mp->m_rtdev_targp->bt_bdev);
}

View File

@ -521,7 +521,8 @@ xfs_trans_log_buf(
{
struct xfs_buf_log_item *bip = bp->b_log_item;
ASSERT(first <= last && last < BBTOB(bp->b_length));
ASSERT(first <= last);
ASSERT(last < BBTOB(bp->b_length));
ASSERT(!(bip->bli_flags & XFS_BLI_ORDERED));
xfs_trans_dirty_buf(tp, bp);

View File

@ -793,17 +793,35 @@ xfs_get_cached_zone(
rcu_read_lock();
oz = VFS_I(ip)->i_private;
if (oz) {
/*
* GC only steals open zones at mount time, so no GC zones
* should end up in the cache.
*/
ASSERT(!oz->oz_is_gc);
if (!atomic_inc_not_zero(&oz->oz_ref))
oz = NULL;
}
rcu_read_unlock();
if (!oz)
goto out_unlock;
/*
* GC only steals open zones at mount time, so no GC zones should end up
* in the cache.
*/
ASSERT(!oz->oz_is_gc);
/*
* Drop the old cached open zone if it is full.
*/
if (oz->oz_allocated == rtg_blocks(oz->oz_rtg)) {
spin_lock(&ip->i_flags_lock);
oz = VFS_I(ip)->i_private;
if (oz && oz->oz_allocated == rtg_blocks(oz->oz_rtg)) {
VFS_I(ip)->i_private = NULL;
spin_unlock(&ip->i_flags_lock);
xfs_open_zone_put(oz);
oz = NULL;
goto out_unlock;
}
spin_unlock(&ip->i_flags_lock);
}
if (!atomic_inc_not_zero(&oz->oz_ref))
oz = NULL;
out_unlock:
rcu_read_unlock();
return oz;
}
@ -818,18 +836,41 @@ xfs_get_cached_zone(
* that were every written to, but significantly simplifies the cached zone
* lookup. Because the open_zone is clearly marked as full when all data
* in the underlying RTG was written, the caching is always safe.
*
* Called with a reference on @oz held. And returns two references on the
* returned zone: one for the caller and one for pinning the zone in
* inode->i_private.
*/
static void
static struct xfs_open_zone *
xfs_set_cached_zone(
struct xfs_inode *ip,
struct xfs_open_zone *oz)
{
struct xfs_open_zone *old_oz;
/*
* If the open zone cached in the inode still has free space, use that
* instead of the new open zone just selected. This can happen when
* multiple threads race to perform zone selection for an inode.
* io_uring worker threads seem to be good way to trigger this.
*
* We need to grab an extra reference to this open zone as the caller
* owns a reference in addition to the i_private pointer.
*/
spin_lock(&ip->i_flags_lock);
old_oz = VFS_I(ip)->i_private;
if (old_oz && old_oz->oz_allocated < rtg_blocks(old_oz->oz_rtg) &&
atomic_inc_not_zero(&old_oz->oz_ref)) {
spin_unlock(&ip->i_flags_lock);
xfs_open_zone_put(oz);
return old_oz;
}
VFS_I(ip)->i_private = oz;
atomic_inc(&oz->oz_ref);
old_oz = xchg(&VFS_I(ip)->i_private, oz);
spin_unlock(&ip->i_flags_lock);
if (old_oz)
xfs_open_zone_put(old_oz);
return oz;
}
static void
@ -873,14 +914,13 @@ xfs_zone_alloc_and_submit(
* the inode is still associated with a zone and use that if so.
*/
if (!*oz)
*oz = xfs_get_cached_zone(ip);
if (!*oz) {
select_zone:
*oz = xfs_get_cached_zone(ip);
if (!*oz) {
*oz = xfs_select_zone(mp, write_hint, pack_tight);
if (!*oz)
goto out_error;
xfs_set_cached_zone(ip, *oz);
*oz = xfs_set_cached_zone(ip, *oz);
}
alloc_len = xfs_zone_alloc_blocks(*oz, XFS_B_TO_FSB(mp, ioend->io_size),

View File

@ -869,6 +869,11 @@ xfs_zone_gc_write_chunk(
WRITE_ONCE(chunk->state, XFS_GC_BIO_NEW);
list_move_tail(&chunk->entry, &data->writing);
/*
* If we run on top of stacked block device, the read I/O might have
* reset bi_bdev, restore it to the one we want.
*/
bio_set_dev(&chunk->bio, mp->m_rtdev_targp->bt_bdev);
bio_reuse(&chunk->bio, REQ_OP_WRITE);
while ((split_chunk = xfs_zone_gc_split_write(data, chunk)))
xfs_zone_gc_submit_write(data, split_chunk);

View File

@ -145,6 +145,7 @@ extern bool has_capability_noaudit(struct task_struct *t, int cap);
extern bool has_ns_capability_noaudit(struct task_struct *t,
struct user_namespace *ns, int cap);
extern bool capable(int cap);
bool capable_noaudit(int cap);
extern bool ns_capable(struct user_namespace *ns, int cap);
extern bool ns_capable_noaudit(struct user_namespace *ns, int cap);
extern bool ns_capable_setid(struct user_namespace *ns, int cap);
@ -167,6 +168,10 @@ static inline bool capable(int cap)
{
return true;
}
static inline bool capable_noaudit(int cap)
{
return true;
}
static inline bool ns_capable(struct user_namespace *ns, int cap)
{
return true;

View File

@ -326,7 +326,6 @@ bool has_capability_noaudit(struct task_struct *t, int cap)
{
return has_ns_capability_noaudit(t, &init_user_ns, cap);
}
EXPORT_SYMBOL(has_capability_noaudit);
static bool ns_capable_common(struct user_namespace *ns,
int cap,
@ -416,6 +415,24 @@ bool capable(int cap)
return ns_capable(&init_user_ns, cap);
}
EXPORT_SYMBOL(capable);
/**
* capable_noaudit - Determine if the current task has a superior
* capability in effect by checking the process's effective
* capabilities (unaudited).
* @cap: The capability to be tested for
*
* This is the same as capable(), except it uses CAP_OPT_NOAUDIT as to prevent
* issuing spurious audit messages.
*
* This sets PF_SUPERPRIV on the task if the capability is available on the
* assumption that it's about to be used.
*/
bool capable_noaudit(int cap)
{
return ns_capable_noaudit(&init_user_ns, cap);
}
EXPORT_SYMBOL(capable_noaudit);
#endif /* CONFIG_MULTIUSER */
/**