XFS bug fies for 6.12-rc6
* fix a sysbot reported crash on filestreams * Reduce cpu time spent searching for extents in a very fragmented FS * Check for delayed allocations before setting extsize Signed-off-by: Carlos Maiolino <cem@kernel.org> -----BEGIN PGP SIGNATURE----- iJUEABMJAB0WIQQMHYkcUKcy4GgPe2RGdaER5QtfpgUCZyIMDwAKCRBGdaER5Qtf pllxAYCkk+mtDTD5xBfOVGZWO5MMFz8HqYcro5wrSCzgL8HDmW29kXTBYFviGn3R 3l/H6BEBgOk0EkI5qGOzijpzbsWyJeLzPzZtxQFPD8zFBdxSERCtbpqFDLLvLQWG M+TLhUNkPQ== =kKX4 -----END PGP SIGNATURE----- Merge tag 'xfs-6.12-fixes-6' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux Pull xfs fixes from Carlos Maiolino: - fix a sysbot reported crash on filestreams - Reduce cpu time spent searching for extents in a very fragmented FS - Check for delayed allocations before setting extsize * tag 'xfs-6.12-fixes-6' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: xfs: streamline xfs_filestream_pick_ag xfs: fix finding a last resort AG in xfs_filestream_pick_ag xfs: Reduce unnecessary searches when searching for the best extents xfs: Check for delayed allocations before setting extsize
This commit is contained in:
commit
f6a7b4ec74
@ -1923,7 +1923,7 @@ restart:
|
||||
error = -EFSCORRUPTED;
|
||||
goto error0;
|
||||
}
|
||||
if (flen < bestrlen)
|
||||
if (flen <= bestrlen)
|
||||
break;
|
||||
busy = xfs_alloc_compute_aligned(args, fbno, flen,
|
||||
&rbno, &rlen, &busy_gen);
|
||||
|
@ -64,26 +64,32 @@ xfs_filestream_pick_ag(
|
||||
struct xfs_perag *pag;
|
||||
struct xfs_perag *max_pag = NULL;
|
||||
xfs_extlen_t minlen = *longest;
|
||||
xfs_extlen_t free = 0, minfree, maxfree = 0;
|
||||
xfs_extlen_t minfree, maxfree = 0;
|
||||
xfs_agnumber_t agno;
|
||||
bool first_pass = true;
|
||||
int err;
|
||||
|
||||
/* 2% of an AG's blocks must be free for it to be chosen. */
|
||||
minfree = mp->m_sb.sb_agblocks / 50;
|
||||
|
||||
restart:
|
||||
for_each_perag_wrap(mp, start_agno, agno, pag) {
|
||||
int err;
|
||||
|
||||
trace_xfs_filestream_scan(pag, pino);
|
||||
|
||||
*longest = 0;
|
||||
err = xfs_bmap_longest_free_extent(pag, NULL, longest);
|
||||
if (err) {
|
||||
if (err != -EAGAIN)
|
||||
break;
|
||||
if (err == -EAGAIN) {
|
||||
/* Couldn't lock the AGF, skip this AG. */
|
||||
err = 0;
|
||||
continue;
|
||||
}
|
||||
xfs_perag_rele(pag);
|
||||
if (max_pag)
|
||||
xfs_perag_rele(max_pag);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Keep track of the AG with the most free blocks. */
|
||||
if (pag->pagf_freeblks > maxfree) {
|
||||
@ -107,8 +113,9 @@ restart:
|
||||
!(flags & XFS_PICK_USERDATA) ||
|
||||
(flags & XFS_PICK_LOWSPACE))) {
|
||||
/* Break out, retaining the reference on the AG. */
|
||||
free = pag->pagf_freeblks;
|
||||
break;
|
||||
if (max_pag)
|
||||
xfs_perag_rele(max_pag);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,18 +123,10 @@ restart:
|
||||
atomic_dec(&pag->pagf_fstrms);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
xfs_perag_rele(pag);
|
||||
if (max_pag)
|
||||
xfs_perag_rele(max_pag);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!pag) {
|
||||
/*
|
||||
* Allow a second pass to give xfs_bmap_longest_free_extent()
|
||||
* another attempt at locking AGFs that it might have skipped
|
||||
* over before we fail.
|
||||
* Allow a second pass to give xfs_bmap_longest_free_extent() another
|
||||
* attempt at locking AGFs that it might have skipped over before we
|
||||
* fail.
|
||||
*/
|
||||
if (first_pass) {
|
||||
first_pass = false;
|
||||
@ -135,8 +134,8 @@ restart:
|
||||
}
|
||||
|
||||
/*
|
||||
* We must be low on data space, so run a final lowspace
|
||||
* optimised selection pass if we haven't already.
|
||||
* We must be low on data space, so run a final lowspace optimised
|
||||
* selection pass if we haven't already.
|
||||
*/
|
||||
if (!(flags & XFS_PICK_LOWSPACE)) {
|
||||
flags |= XFS_PICK_LOWSPACE;
|
||||
@ -144,29 +143,27 @@ restart:
|
||||
}
|
||||
|
||||
/*
|
||||
* No unassociated AGs are available, so select the AG with the
|
||||
* most free space, regardless of whether it's already in use by
|
||||
* another filestream. It none suit, just use whatever AG we can
|
||||
* grab.
|
||||
* No unassociated AGs are available, so select the AG with the most
|
||||
* free space, regardless of whether it's already in use by another
|
||||
* filestream. It none suit, just use whatever AG we can grab.
|
||||
*/
|
||||
if (!max_pag) {
|
||||
for_each_perag_wrap(args->mp, 0, start_agno, args->pag)
|
||||
for_each_perag_wrap(args->mp, 0, start_agno, pag) {
|
||||
max_pag = pag;
|
||||
break;
|
||||
atomic_inc(&args->pag->pagf_fstrms);
|
||||
*longest = 0;
|
||||
} else {
|
||||
pag = max_pag;
|
||||
free = maxfree;
|
||||
atomic_inc(&pag->pagf_fstrms);
|
||||
}
|
||||
} else if (max_pag) {
|
||||
xfs_perag_rele(max_pag);
|
||||
}
|
||||
|
||||
trace_xfs_filestream_pick(pag, pino, free);
|
||||
/* Bail if there are no AGs at all to select from. */
|
||||
if (!max_pag)
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
pag = max_pag;
|
||||
atomic_inc(&pag->pagf_fstrms);
|
||||
done:
|
||||
trace_xfs_filestream_pick(pag, pino);
|
||||
args->pag = pag;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static struct xfs_inode *
|
||||
|
@ -1409,7 +1409,7 @@ xfs_inactive(
|
||||
|
||||
if (S_ISREG(VFS_I(ip)->i_mode) &&
|
||||
(ip->i_disk_size != 0 || XFS_ISIZE(ip) != 0 ||
|
||||
ip->i_df.if_nextents > 0 || ip->i_delayed_blks > 0))
|
||||
xfs_inode_has_filedata(ip)))
|
||||
truncate = 1;
|
||||
|
||||
if (xfs_iflags_test(ip, XFS_IQUOTAUNCHECKED)) {
|
||||
|
@ -292,6 +292,11 @@ static inline bool xfs_is_cow_inode(struct xfs_inode *ip)
|
||||
return xfs_is_reflink_inode(ip) || xfs_is_always_cow_inode(ip);
|
||||
}
|
||||
|
||||
static inline bool xfs_inode_has_filedata(const struct xfs_inode *ip)
|
||||
{
|
||||
return ip->i_df.if_nextents > 0 || ip->i_delayed_blks > 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if an inode has any data in the COW fork. This might be often false
|
||||
* even for inodes with the reflink flag when there is no pending COW operation.
|
||||
|
@ -481,7 +481,7 @@ xfs_ioctl_setattr_xflags(
|
||||
|
||||
if (rtflag != XFS_IS_REALTIME_INODE(ip)) {
|
||||
/* Can't change realtime flag if any extents are allocated. */
|
||||
if (ip->i_df.if_nextents || ip->i_delayed_blks)
|
||||
if (xfs_inode_has_filedata(ip))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
@ -602,7 +602,7 @@ xfs_ioctl_setattr_check_extsize(
|
||||
if (!fa->fsx_valid)
|
||||
return 0;
|
||||
|
||||
if (S_ISREG(VFS_I(ip)->i_mode) && ip->i_df.if_nextents &&
|
||||
if (S_ISREG(VFS_I(ip)->i_mode) && xfs_inode_has_filedata(ip) &&
|
||||
XFS_FSB_TO_B(mp, ip->i_extsize) != fa->fsx_extsize)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -691,8 +691,8 @@ DEFINE_FILESTREAM_EVENT(xfs_filestream_lookup);
|
||||
DEFINE_FILESTREAM_EVENT(xfs_filestream_scan);
|
||||
|
||||
TRACE_EVENT(xfs_filestream_pick,
|
||||
TP_PROTO(struct xfs_perag *pag, xfs_ino_t ino, xfs_extlen_t free),
|
||||
TP_ARGS(pag, ino, free),
|
||||
TP_PROTO(struct xfs_perag *pag, xfs_ino_t ino),
|
||||
TP_ARGS(pag, ino),
|
||||
TP_STRUCT__entry(
|
||||
__field(dev_t, dev)
|
||||
__field(xfs_ino_t, ino)
|
||||
@ -703,14 +703,9 @@ TRACE_EVENT(xfs_filestream_pick,
|
||||
TP_fast_assign(
|
||||
__entry->dev = pag->pag_mount->m_super->s_dev;
|
||||
__entry->ino = ino;
|
||||
if (pag) {
|
||||
__entry->agno = pag->pag_agno;
|
||||
__entry->streams = atomic_read(&pag->pagf_fstrms);
|
||||
} else {
|
||||
__entry->agno = NULLAGNUMBER;
|
||||
__entry->streams = 0;
|
||||
}
|
||||
__entry->free = free;
|
||||
__entry->free = pag->pagf_freeblks;
|
||||
),
|
||||
TP_printk("dev %d:%d ino 0x%llx agno 0x%x streams %d free %d",
|
||||
MAJOR(__entry->dev), MINOR(__entry->dev),
|
||||
|
Loading…
Reference in New Issue
Block a user