Skip to content

Commit f6a7b4e

Browse files
committed
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
2 parents 1106680 + 81a1e1c commit f6a7b4e

File tree

6 files changed

+62
-65
lines changed

6 files changed

+62
-65
lines changed

fs/xfs/libxfs/xfs_alloc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1923,7 +1923,7 @@ xfs_alloc_ag_vextent_size(
19231923
error = -EFSCORRUPTED;
19241924
goto error0;
19251925
}
1926-
if (flen < bestrlen)
1926+
if (flen <= bestrlen)
19271927
break;
19281928
busy = xfs_alloc_compute_aligned(args, fbno, flen,
19291929
&rbno, &rlen, &busy_gen);

fs/xfs/xfs_filestream.c

Lines changed: 48 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -64,25 +64,31 @@ xfs_filestream_pick_ag(
6464
struct xfs_perag *pag;
6565
struct xfs_perag *max_pag = NULL;
6666
xfs_extlen_t minlen = *longest;
67-
xfs_extlen_t free = 0, minfree, maxfree = 0;
67+
xfs_extlen_t minfree, maxfree = 0;
6868
xfs_agnumber_t agno;
6969
bool first_pass = true;
70-
int err;
7170

7271
/* 2% of an AG's blocks must be free for it to be chosen. */
7372
minfree = mp->m_sb.sb_agblocks / 50;
7473

7574
restart:
7675
for_each_perag_wrap(mp, start_agno, agno, pag) {
76+
int err;
77+
7778
trace_xfs_filestream_scan(pag, pino);
79+
7880
*longest = 0;
7981
err = xfs_bmap_longest_free_extent(pag, NULL, longest);
8082
if (err) {
81-
if (err != -EAGAIN)
82-
break;
83-
/* Couldn't lock the AGF, skip this AG. */
84-
err = 0;
85-
continue;
83+
if (err == -EAGAIN) {
84+
/* Couldn't lock the AGF, skip this AG. */
85+
err = 0;
86+
continue;
87+
}
88+
xfs_perag_rele(pag);
89+
if (max_pag)
90+
xfs_perag_rele(max_pag);
91+
return err;
8692
}
8793

8894
/* Keep track of the AG with the most free blocks. */
@@ -107,66 +113,57 @@ xfs_filestream_pick_ag(
107113
!(flags & XFS_PICK_USERDATA) ||
108114
(flags & XFS_PICK_LOWSPACE))) {
109115
/* Break out, retaining the reference on the AG. */
110-
free = pag->pagf_freeblks;
111-
break;
116+
if (max_pag)
117+
xfs_perag_rele(max_pag);
118+
goto done;
112119
}
113120
}
114121

115122
/* Drop the reference on this AG, it's not usable. */
116123
atomic_dec(&pag->pagf_fstrms);
117124
}
118125

119-
if (err) {
120-
xfs_perag_rele(pag);
121-
if (max_pag)
122-
xfs_perag_rele(max_pag);
123-
return err;
126+
/*
127+
* Allow a second pass to give xfs_bmap_longest_free_extent() another
128+
* attempt at locking AGFs that it might have skipped over before we
129+
* fail.
130+
*/
131+
if (first_pass) {
132+
first_pass = false;
133+
goto restart;
124134
}
125135

126-
if (!pag) {
127-
/*
128-
* Allow a second pass to give xfs_bmap_longest_free_extent()
129-
* another attempt at locking AGFs that it might have skipped
130-
* over before we fail.
131-
*/
132-
if (first_pass) {
133-
first_pass = false;
134-
goto restart;
135-
}
136+
/*
137+
* We must be low on data space, so run a final lowspace optimised
138+
* selection pass if we haven't already.
139+
*/
140+
if (!(flags & XFS_PICK_LOWSPACE)) {
141+
flags |= XFS_PICK_LOWSPACE;
142+
goto restart;
143+
}
136144

137-
/*
138-
* We must be low on data space, so run a final lowspace
139-
* optimised selection pass if we haven't already.
140-
*/
141-
if (!(flags & XFS_PICK_LOWSPACE)) {
142-
flags |= XFS_PICK_LOWSPACE;
143-
goto restart;
145+
/*
146+
* No unassociated AGs are available, so select the AG with the most
147+
* free space, regardless of whether it's already in use by another
148+
* filestream. It none suit, just use whatever AG we can grab.
149+
*/
150+
if (!max_pag) {
151+
for_each_perag_wrap(args->mp, 0, start_agno, pag) {
152+
max_pag = pag;
153+
break;
144154
}
145155

146-
/*
147-
* No unassociated AGs are available, so select the AG with the
148-
* most free space, regardless of whether it's already in use by
149-
* another filestream. It none suit, just use whatever AG we can
150-
* grab.
151-
*/
152-
if (!max_pag) {
153-
for_each_perag_wrap(args->mp, 0, start_agno, args->pag)
154-
break;
155-
atomic_inc(&args->pag->pagf_fstrms);
156-
*longest = 0;
157-
} else {
158-
pag = max_pag;
159-
free = maxfree;
160-
atomic_inc(&pag->pagf_fstrms);
161-
}
162-
} else if (max_pag) {
163-
xfs_perag_rele(max_pag);
156+
/* Bail if there are no AGs at all to select from. */
157+
if (!max_pag)
158+
return -ENOSPC;
164159
}
165160

166-
trace_xfs_filestream_pick(pag, pino, free);
161+
pag = max_pag;
162+
atomic_inc(&pag->pagf_fstrms);
163+
done:
164+
trace_xfs_filestream_pick(pag, pino);
167165
args->pag = pag;
168166
return 0;
169-
170167
}
171168

172169
static struct xfs_inode *

fs/xfs/xfs_inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1409,7 +1409,7 @@ xfs_inactive(
14091409

14101410
if (S_ISREG(VFS_I(ip)->i_mode) &&
14111411
(ip->i_disk_size != 0 || XFS_ISIZE(ip) != 0 ||
1412-
ip->i_df.if_nextents > 0 || ip->i_delayed_blks > 0))
1412+
xfs_inode_has_filedata(ip)))
14131413
truncate = 1;
14141414

14151415
if (xfs_iflags_test(ip, XFS_IQUOTAUNCHECKED)) {

fs/xfs/xfs_inode.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,11 @@ static inline bool xfs_is_cow_inode(struct xfs_inode *ip)
292292
return xfs_is_reflink_inode(ip) || xfs_is_always_cow_inode(ip);
293293
}
294294

295+
static inline bool xfs_inode_has_filedata(const struct xfs_inode *ip)
296+
{
297+
return ip->i_df.if_nextents > 0 || ip->i_delayed_blks > 0;
298+
}
299+
295300
/*
296301
* Check if an inode has any data in the COW fork. This might be often false
297302
* even for inodes with the reflink flag when there is no pending COW operation.

fs/xfs/xfs_ioctl.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ xfs_ioctl_setattr_xflags(
481481

482482
if (rtflag != XFS_IS_REALTIME_INODE(ip)) {
483483
/* Can't change realtime flag if any extents are allocated. */
484-
if (ip->i_df.if_nextents || ip->i_delayed_blks)
484+
if (xfs_inode_has_filedata(ip))
485485
return -EINVAL;
486486

487487
/*
@@ -602,7 +602,7 @@ xfs_ioctl_setattr_check_extsize(
602602
if (!fa->fsx_valid)
603603
return 0;
604604

605-
if (S_ISREG(VFS_I(ip)->i_mode) && ip->i_df.if_nextents &&
605+
if (S_ISREG(VFS_I(ip)->i_mode) && xfs_inode_has_filedata(ip) &&
606606
XFS_FSB_TO_B(mp, ip->i_extsize) != fa->fsx_extsize)
607607
return -EINVAL;
608608

fs/xfs/xfs_trace.h

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -691,8 +691,8 @@ DEFINE_FILESTREAM_EVENT(xfs_filestream_lookup);
691691
DEFINE_FILESTREAM_EVENT(xfs_filestream_scan);
692692

693693
TRACE_EVENT(xfs_filestream_pick,
694-
TP_PROTO(struct xfs_perag *pag, xfs_ino_t ino, xfs_extlen_t free),
695-
TP_ARGS(pag, ino, free),
694+
TP_PROTO(struct xfs_perag *pag, xfs_ino_t ino),
695+
TP_ARGS(pag, ino),
696696
TP_STRUCT__entry(
697697
__field(dev_t, dev)
698698
__field(xfs_ino_t, ino)
@@ -703,14 +703,9 @@ TRACE_EVENT(xfs_filestream_pick,
703703
TP_fast_assign(
704704
__entry->dev = pag->pag_mount->m_super->s_dev;
705705
__entry->ino = ino;
706-
if (pag) {
707-
__entry->agno = pag->pag_agno;
708-
__entry->streams = atomic_read(&pag->pagf_fstrms);
709-
} else {
710-
__entry->agno = NULLAGNUMBER;
711-
__entry->streams = 0;
712-
}
713-
__entry->free = free;
706+
__entry->agno = pag->pag_agno;
707+
__entry->streams = atomic_read(&pag->pagf_fstrms);
708+
__entry->free = pag->pagf_freeblks;
714709
),
715710
TP_printk("dev %d:%d ino 0x%llx agno 0x%x streams %d free %d",
716711
MAJOR(__entry->dev), MINOR(__entry->dev),

0 commit comments

Comments
 (0)