Skip to content

Commit 9d5e849

Browse files
author
Darrick J. Wong
committed
xfs: adjust rt allocation minlen when extszhint > rtextsize
xfs_bmap_rtalloc doesn't handle realtime extent files with extent size hints larger than the rt volume's extent size properly, because xfs_bmap_extsize_align can adjust the offset/length parameters to try to fit the extent size hint. Under these conditions, minlen has to be large enough so that any allocation returned by xfs_rtallocate_extent will be large enough to cover at least one of the blocks that the caller asked for. If the allocation is too short, bmapi_write will return no mapping for the requested range, which causes ENOSPC errors in other parts of the filesystem. Therefore, adjust minlen upwards to fix this. This can be found by running generic/263 (g/127 or g/522) with a realtime extent size hint that's larger than the rt volume extent size. Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Allison Henderson <[email protected]>
1 parent d07f6ca commit 9d5e849

File tree

1 file changed

+57
-26
lines changed

1 file changed

+57
-26
lines changed

fs/xfs/xfs_bmap_util.c

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -71,18 +71,23 @@ xfs_zero_extent(
7171
#ifdef CONFIG_XFS_RT
7272
int
7373
xfs_bmap_rtalloc(
74-
struct xfs_bmalloca *ap) /* bmap alloc argument struct */
74+
struct xfs_bmalloca *ap)
7575
{
76-
int error; /* error return value */
77-
xfs_mount_t *mp; /* mount point structure */
78-
xfs_extlen_t prod = 0; /* product factor for allocators */
79-
xfs_extlen_t mod = 0; /* product factor for allocators */
80-
xfs_extlen_t ralen = 0; /* realtime allocation length */
81-
xfs_extlen_t align; /* minimum allocation alignment */
82-
xfs_rtblock_t rtb;
83-
84-
mp = ap->ip->i_mount;
76+
struct xfs_mount *mp = ap->ip->i_mount;
77+
xfs_fileoff_t orig_offset = ap->offset;
78+
xfs_rtblock_t rtb;
79+
xfs_extlen_t prod = 0; /* product factor for allocators */
80+
xfs_extlen_t mod = 0; /* product factor for allocators */
81+
xfs_extlen_t ralen = 0; /* realtime allocation length */
82+
xfs_extlen_t align; /* minimum allocation alignment */
83+
xfs_extlen_t orig_length = ap->length;
84+
xfs_extlen_t minlen = mp->m_sb.sb_rextsize;
85+
xfs_extlen_t raminlen;
86+
bool rtlocked = false;
87+
int error;
88+
8589
align = xfs_get_extsz_hint(ap->ip);
90+
retry:
8691
prod = align / mp->m_sb.sb_rextsize;
8792
error = xfs_bmap_extsize_align(mp, &ap->got, &ap->prev,
8893
align, 1, ap->eof, 0,
@@ -92,6 +97,15 @@ xfs_bmap_rtalloc(
9297
ASSERT(ap->length);
9398
ASSERT(ap->length % mp->m_sb.sb_rextsize == 0);
9499

100+
/*
101+
* If we shifted the file offset downward to satisfy an extent size
102+
* hint, increase minlen by that amount so that the allocator won't
103+
* give us an allocation that's too short to cover at least one of the
104+
* blocks that the caller asked for.
105+
*/
106+
if (ap->offset != orig_offset)
107+
minlen += orig_offset - ap->offset;
108+
95109
/*
96110
* If the offset & length are not perfectly aligned
97111
* then kill prod, it will just get us in trouble.
@@ -116,10 +130,13 @@ xfs_bmap_rtalloc(
116130
/*
117131
* Lock out modifications to both the RT bitmap and summary inodes
118132
*/
119-
xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL|XFS_ILOCK_RTBITMAP);
120-
xfs_trans_ijoin(ap->tp, mp->m_rbmip, XFS_ILOCK_EXCL);
121-
xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL|XFS_ILOCK_RTSUM);
122-
xfs_trans_ijoin(ap->tp, mp->m_rsumip, XFS_ILOCK_EXCL);
133+
if (!rtlocked) {
134+
xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL|XFS_ILOCK_RTBITMAP);
135+
xfs_trans_ijoin(ap->tp, mp->m_rbmip, XFS_ILOCK_EXCL);
136+
xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL|XFS_ILOCK_RTSUM);
137+
xfs_trans_ijoin(ap->tp, mp->m_rsumip, XFS_ILOCK_EXCL);
138+
rtlocked = true;
139+
}
123140

124141
/*
125142
* If it's an allocation to an empty file at offset 0,
@@ -144,30 +161,44 @@ xfs_bmap_rtalloc(
144161
do_div(ap->blkno, mp->m_sb.sb_rextsize);
145162
rtb = ap->blkno;
146163
ap->length = ralen;
147-
error = xfs_rtallocate_extent(ap->tp, ap->blkno, 1, ap->length,
148-
&ralen, ap->wasdel, prod, &rtb);
164+
raminlen = max_t(xfs_extlen_t, 1, minlen / mp->m_sb.sb_rextsize);
165+
error = xfs_rtallocate_extent(ap->tp, ap->blkno, raminlen, ap->length,
166+
&ralen, ap->wasdel, prod, &rtb);
149167
if (error)
150168
return error;
151169

152-
ap->blkno = rtb;
153-
if (ap->blkno != NULLFSBLOCK) {
154-
ap->blkno *= mp->m_sb.sb_rextsize;
155-
ralen *= mp->m_sb.sb_rextsize;
156-
ap->length = ralen;
157-
ap->ip->i_nblocks += ralen;
170+
if (rtb != NULLRTBLOCK) {
171+
ap->blkno = rtb * mp->m_sb.sb_rextsize;
172+
ap->length = ralen * mp->m_sb.sb_rextsize;
173+
ap->ip->i_nblocks += ap->length;
158174
xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE);
159175
if (ap->wasdel)
160-
ap->ip->i_delayed_blks -= ralen;
176+
ap->ip->i_delayed_blks -= ap->length;
161177
/*
162178
* Adjust the disk quota also. This was reserved
163179
* earlier.
164180
*/
165181
xfs_trans_mod_dquot_byino(ap->tp, ap->ip,
166182
ap->wasdel ? XFS_TRANS_DQ_DELRTBCOUNT :
167-
XFS_TRANS_DQ_RTBCOUNT, (long) ralen);
168-
} else {
169-
ap->length = 0;
183+
XFS_TRANS_DQ_RTBCOUNT, ap->length);
184+
return 0;
185+
}
186+
187+
if (align > mp->m_sb.sb_rextsize) {
188+
/*
189+
* We previously enlarged the request length to try to satisfy
190+
* an extent size hint. The allocator didn't return anything,
191+
* so reset the parameters to the original values and try again
192+
* without alignment criteria.
193+
*/
194+
ap->offset = orig_offset;
195+
ap->length = orig_length;
196+
minlen = align = mp->m_sb.sb_rextsize;
197+
goto retry;
170198
}
199+
200+
ap->blkno = NULLFSBLOCK;
201+
ap->length = 0;
171202
return 0;
172203
}
173204
#endif /* CONFIG_XFS_RT */

0 commit comments

Comments
 (0)