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;
|
error = -EFSCORRUPTED;
|
||||||
goto error0;
|
goto error0;
|
||||||
}
|
}
|
||||||
if (flen < bestrlen)
|
if (flen <= bestrlen)
|
||||||
break;
|
break;
|
||||||
busy = xfs_alloc_compute_aligned(args, fbno, flen,
|
busy = xfs_alloc_compute_aligned(args, fbno, flen,
|
||||||
&rbno, &rlen, &busy_gen);
|
&rbno, &rlen, &busy_gen);
|
||||||
|
@ -64,26 +64,32 @@ xfs_filestream_pick_ag(
|
|||||||
struct xfs_perag *pag;
|
struct xfs_perag *pag;
|
||||||
struct xfs_perag *max_pag = NULL;
|
struct xfs_perag *max_pag = NULL;
|
||||||
xfs_extlen_t minlen = *longest;
|
xfs_extlen_t minlen = *longest;
|
||||||
xfs_extlen_t free = 0, minfree, maxfree = 0;
|
xfs_extlen_t minfree, maxfree = 0;
|
||||||
xfs_agnumber_t agno;
|
xfs_agnumber_t agno;
|
||||||
bool first_pass = true;
|
bool first_pass = true;
|
||||||
int err;
|
|
||||||
|
|
||||||
/* 2% of an AG's blocks must be free for it to be chosen. */
|
/* 2% of an AG's blocks must be free for it to be chosen. */
|
||||||
minfree = mp->m_sb.sb_agblocks / 50;
|
minfree = mp->m_sb.sb_agblocks / 50;
|
||||||
|
|
||||||
restart:
|
restart:
|
||||||
for_each_perag_wrap(mp, start_agno, agno, pag) {
|
for_each_perag_wrap(mp, start_agno, agno, pag) {
|
||||||
|
int err;
|
||||||
|
|
||||||
trace_xfs_filestream_scan(pag, pino);
|
trace_xfs_filestream_scan(pag, pino);
|
||||||
|
|
||||||
*longest = 0;
|
*longest = 0;
|
||||||
err = xfs_bmap_longest_free_extent(pag, NULL, longest);
|
err = xfs_bmap_longest_free_extent(pag, NULL, longest);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err != -EAGAIN)
|
if (err == -EAGAIN) {
|
||||||
break;
|
|
||||||
/* Couldn't lock the AGF, skip this AG. */
|
/* Couldn't lock the AGF, skip this AG. */
|
||||||
err = 0;
|
err = 0;
|
||||||
continue;
|
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. */
|
/* Keep track of the AG with the most free blocks. */
|
||||||
if (pag->pagf_freeblks > maxfree) {
|
if (pag->pagf_freeblks > maxfree) {
|
||||||
@ -107,8 +113,9 @@ restart:
|
|||||||
!(flags & XFS_PICK_USERDATA) ||
|
!(flags & XFS_PICK_USERDATA) ||
|
||||||
(flags & XFS_PICK_LOWSPACE))) {
|
(flags & XFS_PICK_LOWSPACE))) {
|
||||||
/* Break out, retaining the reference on the AG. */
|
/* Break out, retaining the reference on the AG. */
|
||||||
free = pag->pagf_freeblks;
|
if (max_pag)
|
||||||
break;
|
xfs_perag_rele(max_pag);
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,18 +123,10 @@ restart:
|
|||||||
atomic_dec(&pag->pagf_fstrms);
|
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()
|
* Allow a second pass to give xfs_bmap_longest_free_extent() another
|
||||||
* another attempt at locking AGFs that it might have skipped
|
* attempt at locking AGFs that it might have skipped over before we
|
||||||
* over before we fail.
|
* fail.
|
||||||
*/
|
*/
|
||||||
if (first_pass) {
|
if (first_pass) {
|
||||||
first_pass = false;
|
first_pass = false;
|
||||||
@ -135,8 +134,8 @@ restart:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We must be low on data space, so run a final lowspace
|
* We must be low on data space, so run a final lowspace optimised
|
||||||
* optimised selection pass if we haven't already.
|
* selection pass if we haven't already.
|
||||||
*/
|
*/
|
||||||
if (!(flags & XFS_PICK_LOWSPACE)) {
|
if (!(flags & XFS_PICK_LOWSPACE)) {
|
||||||
flags |= XFS_PICK_LOWSPACE;
|
flags |= XFS_PICK_LOWSPACE;
|
||||||
@ -144,29 +143,27 @@ restart:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No unassociated AGs are available, so select the AG with the
|
* No unassociated AGs are available, so select the AG with the most
|
||||||
* most free space, regardless of whether it's already in use by
|
* free space, regardless of whether it's already in use by another
|
||||||
* another filestream. It none suit, just use whatever AG we can
|
* filestream. It none suit, just use whatever AG we can grab.
|
||||||
* grab.
|
|
||||||
*/
|
*/
|
||||||
if (!max_pag) {
|
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;
|
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;
|
args->pag = pag;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct xfs_inode *
|
static struct xfs_inode *
|
||||||
|
@ -1409,7 +1409,7 @@ xfs_inactive(
|
|||||||
|
|
||||||
if (S_ISREG(VFS_I(ip)->i_mode) &&
|
if (S_ISREG(VFS_I(ip)->i_mode) &&
|
||||||
(ip->i_disk_size != 0 || XFS_ISIZE(ip) != 0 ||
|
(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;
|
truncate = 1;
|
||||||
|
|
||||||
if (xfs_iflags_test(ip, XFS_IQUOTAUNCHECKED)) {
|
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);
|
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
|
* 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.
|
* 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)) {
|
if (rtflag != XFS_IS_REALTIME_INODE(ip)) {
|
||||||
/* Can't change realtime flag if any extents are allocated. */
|
/* 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;
|
return -EINVAL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -602,7 +602,7 @@ xfs_ioctl_setattr_check_extsize(
|
|||||||
if (!fa->fsx_valid)
|
if (!fa->fsx_valid)
|
||||||
return 0;
|
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)
|
XFS_FSB_TO_B(mp, ip->i_extsize) != fa->fsx_extsize)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -691,8 +691,8 @@ DEFINE_FILESTREAM_EVENT(xfs_filestream_lookup);
|
|||||||
DEFINE_FILESTREAM_EVENT(xfs_filestream_scan);
|
DEFINE_FILESTREAM_EVENT(xfs_filestream_scan);
|
||||||
|
|
||||||
TRACE_EVENT(xfs_filestream_pick,
|
TRACE_EVENT(xfs_filestream_pick,
|
||||||
TP_PROTO(struct xfs_perag *pag, xfs_ino_t ino, xfs_extlen_t free),
|
TP_PROTO(struct xfs_perag *pag, xfs_ino_t ino),
|
||||||
TP_ARGS(pag, ino, free),
|
TP_ARGS(pag, ino),
|
||||||
TP_STRUCT__entry(
|
TP_STRUCT__entry(
|
||||||
__field(dev_t, dev)
|
__field(dev_t, dev)
|
||||||
__field(xfs_ino_t, ino)
|
__field(xfs_ino_t, ino)
|
||||||
@ -703,14 +703,9 @@ TRACE_EVENT(xfs_filestream_pick,
|
|||||||
TP_fast_assign(
|
TP_fast_assign(
|
||||||
__entry->dev = pag->pag_mount->m_super->s_dev;
|
__entry->dev = pag->pag_mount->m_super->s_dev;
|
||||||
__entry->ino = ino;
|
__entry->ino = ino;
|
||||||
if (pag) {
|
|
||||||
__entry->agno = pag->pag_agno;
|
__entry->agno = pag->pag_agno;
|
||||||
__entry->streams = atomic_read(&pag->pagf_fstrms);
|
__entry->streams = atomic_read(&pag->pagf_fstrms);
|
||||||
} else {
|
__entry->free = pag->pagf_freeblks;
|
||||||
__entry->agno = NULLAGNUMBER;
|
|
||||||
__entry->streams = 0;
|
|
||||||
}
|
|
||||||
__entry->free = free;
|
|
||||||
),
|
),
|
||||||
TP_printk("dev %d:%d ino 0x%llx agno 0x%x streams %d free %d",
|
TP_printk("dev %d:%d ino 0x%llx agno 0x%x streams %d free %d",
|
||||||
MAJOR(__entry->dev), MINOR(__entry->dev),
|
MAJOR(__entry->dev), MINOR(__entry->dev),
|
||||||
|
Loading…
Reference in New Issue
Block a user