Skip to content

Commit f574943

Browse files
committed
Merge tag 'xfs-4.18-fixes-2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
Pull xfs fixes from Darrick Wong: "Here are some patches for 4.18 to fix regressions, accounting problems, overflow problems, and to strengthen metadata validation to prevent corruption. This series has been run through a full xfstests run over the weekend and through a quick xfstests run against this morning's master, with no major failures reported. Changes since last update: - more metadata validation strengthening to prevent crashes. - fix extent offset overflow problem when insert_range on a 512b block fs - fix some off-by-one errors in the realtime fsmap code - fix some math errors in the default resblks calculation when free space is low - fix a problem where stale page contents are exposed via mmap read after a zero_range at eof - fix accounting problems with per-ag reservations causing statfs reports to vary incorrectly" * tag 'xfs-4.18-fixes-2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: xfs: fix fdblocks accounting w/ RMAPBT per-AG reservation xfs: ensure post-EOF zeroing happens after zeroing part of a file xfs: fix off-by-one error in xfs_rtalloc_query_range xfs: fix uninitialized field in rtbitmap fsmap backend xfs: recheck reflink state after grabbing ILOCK_SHARED for a write xfs: don't allow insert-range to shift extents past the maximum offset xfs: don't trip over negative free space in xfs_reserve_blocks xfs: allow empty transactions while frozen xfs: xfs_iflush_abort() can be called twice on cluster writeback failure xfs: More robust inode extent count validation xfs: simplify xfs_bmap_punch_delalloc_range
2 parents 0e49740 + d8cb5e4 commit f574943

File tree

12 files changed

+205
-130
lines changed

12 files changed

+205
-130
lines changed

fs/xfs/libxfs/xfs_ag_resv.c

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ __xfs_ag_resv_free(
157157
error = xfs_mod_fdblocks(pag->pag_mount, oldresv, true);
158158
resv->ar_reserved = 0;
159159
resv->ar_asked = 0;
160+
resv->ar_orig_reserved = 0;
160161

161162
if (error)
162163
trace_xfs_ag_resv_free_error(pag->pag_mount, pag->pag_agno,
@@ -189,13 +190,34 @@ __xfs_ag_resv_init(
189190
struct xfs_mount *mp = pag->pag_mount;
190191
struct xfs_ag_resv *resv;
191192
int error;
192-
xfs_extlen_t reserved;
193+
xfs_extlen_t hidden_space;
193194

194195
if (used > ask)
195196
ask = used;
196-
reserved = ask - used;
197197

198-
error = xfs_mod_fdblocks(mp, -(int64_t)reserved, true);
198+
switch (type) {
199+
case XFS_AG_RESV_RMAPBT:
200+
/*
201+
* Space taken by the rmapbt is not subtracted from fdblocks
202+
* because the rmapbt lives in the free space. Here we must
203+
* subtract the entire reservation from fdblocks so that we
204+
* always have blocks available for rmapbt expansion.
205+
*/
206+
hidden_space = ask;
207+
break;
208+
case XFS_AG_RESV_METADATA:
209+
/*
210+
* Space taken by all other metadata btrees are accounted
211+
* on-disk as used space. We therefore only hide the space
212+
* that is reserved but not used by the trees.
213+
*/
214+
hidden_space = ask - used;
215+
break;
216+
default:
217+
ASSERT(0);
218+
return -EINVAL;
219+
}
220+
error = xfs_mod_fdblocks(mp, -(int64_t)hidden_space, true);
199221
if (error) {
200222
trace_xfs_ag_resv_init_error(pag->pag_mount, pag->pag_agno,
201223
error, _RET_IP_);
@@ -216,7 +238,8 @@ __xfs_ag_resv_init(
216238

217239
resv = xfs_perag_resv(pag, type);
218240
resv->ar_asked = ask;
219-
resv->ar_reserved = resv->ar_orig_reserved = reserved;
241+
resv->ar_orig_reserved = hidden_space;
242+
resv->ar_reserved = ask - used;
220243

221244
trace_xfs_ag_resv_init(pag, type, ask);
222245
return 0;

fs/xfs/libxfs/xfs_bmap.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5780,6 +5780,32 @@ xfs_bmap_collapse_extents(
57805780
return error;
57815781
}
57825782

5783+
/* Make sure we won't be right-shifting an extent past the maximum bound. */
5784+
int
5785+
xfs_bmap_can_insert_extents(
5786+
struct xfs_inode *ip,
5787+
xfs_fileoff_t off,
5788+
xfs_fileoff_t shift)
5789+
{
5790+
struct xfs_bmbt_irec got;
5791+
int is_empty;
5792+
int error = 0;
5793+
5794+
ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
5795+
5796+
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
5797+
return -EIO;
5798+
5799+
xfs_ilock(ip, XFS_ILOCK_EXCL);
5800+
error = xfs_bmap_last_extent(NULL, ip, XFS_DATA_FORK, &got, &is_empty);
5801+
if (!error && !is_empty && got.br_startoff >= off &&
5802+
((got.br_startoff + shift) & BMBT_STARTOFF_MASK) < got.br_startoff)
5803+
error = -EINVAL;
5804+
xfs_iunlock(ip, XFS_ILOCK_EXCL);
5805+
5806+
return error;
5807+
}
5808+
57835809
int
57845810
xfs_bmap_insert_extents(
57855811
struct xfs_trans *tp,

fs/xfs/libxfs/xfs_bmap.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,8 @@ int xfs_bmap_collapse_extents(struct xfs_trans *tp, struct xfs_inode *ip,
227227
xfs_fileoff_t *next_fsb, xfs_fileoff_t offset_shift_fsb,
228228
bool *done, xfs_fsblock_t *firstblock,
229229
struct xfs_defer_ops *dfops);
230+
int xfs_bmap_can_insert_extents(struct xfs_inode *ip, xfs_fileoff_t off,
231+
xfs_fileoff_t shift);
230232
int xfs_bmap_insert_extents(struct xfs_trans *tp, struct xfs_inode *ip,
231233
xfs_fileoff_t *next_fsb, xfs_fileoff_t offset_shift_fsb,
232234
bool *done, xfs_fileoff_t stop_fsb, xfs_fsblock_t *firstblock,

fs/xfs/libxfs/xfs_format.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -962,6 +962,9 @@ typedef enum xfs_dinode_fmt {
962962
XFS_DFORK_DSIZE(dip, mp) : \
963963
XFS_DFORK_ASIZE(dip, mp))
964964

965+
#define XFS_DFORK_MAXEXT(dip, mp, w) \
966+
(XFS_DFORK_SIZE(dip, mp, w) / sizeof(struct xfs_bmbt_rec))
967+
965968
/*
966969
* Return pointers to the data or attribute forks.
967970
*/
@@ -1526,6 +1529,8 @@ typedef struct xfs_bmdr_block {
15261529
#define BMBT_STARTBLOCK_BITLEN 52
15271530
#define BMBT_BLOCKCOUNT_BITLEN 21
15281531

1532+
#define BMBT_STARTOFF_MASK ((1ULL << BMBT_STARTOFF_BITLEN) - 1)
1533+
15291534
typedef struct xfs_bmbt_rec {
15301535
__be64 l0, l1;
15311536
} xfs_bmbt_rec_t;

fs/xfs/libxfs/xfs_inode_buf.c

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,47 @@ xfs_log_dinode_to_disk(
374374
}
375375
}
376376

377+
static xfs_failaddr_t
378+
xfs_dinode_verify_fork(
379+
struct xfs_dinode *dip,
380+
struct xfs_mount *mp,
381+
int whichfork)
382+
{
383+
uint32_t di_nextents = XFS_DFORK_NEXTENTS(dip, whichfork);
384+
385+
switch (XFS_DFORK_FORMAT(dip, whichfork)) {
386+
case XFS_DINODE_FMT_LOCAL:
387+
/*
388+
* no local regular files yet
389+
*/
390+
if (whichfork == XFS_DATA_FORK) {
391+
if (S_ISREG(be16_to_cpu(dip->di_mode)))
392+
return __this_address;
393+
if (be64_to_cpu(dip->di_size) >
394+
XFS_DFORK_SIZE(dip, mp, whichfork))
395+
return __this_address;
396+
}
397+
if (di_nextents)
398+
return __this_address;
399+
break;
400+
case XFS_DINODE_FMT_EXTENTS:
401+
if (di_nextents > XFS_DFORK_MAXEXT(dip, mp, whichfork))
402+
return __this_address;
403+
break;
404+
case XFS_DINODE_FMT_BTREE:
405+
if (whichfork == XFS_ATTR_FORK) {
406+
if (di_nextents > MAXAEXTNUM)
407+
return __this_address;
408+
} else if (di_nextents > MAXEXTNUM) {
409+
return __this_address;
410+
}
411+
break;
412+
default:
413+
return __this_address;
414+
}
415+
return NULL;
416+
}
417+
377418
xfs_failaddr_t
378419
xfs_dinode_verify(
379420
struct xfs_mount *mp,
@@ -441,24 +482,9 @@ xfs_dinode_verify(
441482
case S_IFREG:
442483
case S_IFLNK:
443484
case S_IFDIR:
444-
switch (dip->di_format) {
445-
case XFS_DINODE_FMT_LOCAL:
446-
/*
447-
* no local regular files yet
448-
*/
449-
if (S_ISREG(mode))
450-
return __this_address;
451-
if (di_size > XFS_DFORK_DSIZE(dip, mp))
452-
return __this_address;
453-
if (dip->di_nextents)
454-
return __this_address;
455-
/* fall through */
456-
case XFS_DINODE_FMT_EXTENTS:
457-
case XFS_DINODE_FMT_BTREE:
458-
break;
459-
default:
460-
return __this_address;
461-
}
485+
fa = xfs_dinode_verify_fork(dip, mp, XFS_DATA_FORK);
486+
if (fa)
487+
return fa;
462488
break;
463489
case 0:
464490
/* Uninitialized inode ok. */
@@ -468,17 +494,9 @@ xfs_dinode_verify(
468494
}
469495

470496
if (XFS_DFORK_Q(dip)) {
471-
switch (dip->di_aformat) {
472-
case XFS_DINODE_FMT_LOCAL:
473-
if (dip->di_anextents)
474-
return __this_address;
475-
/* fall through */
476-
case XFS_DINODE_FMT_EXTENTS:
477-
case XFS_DINODE_FMT_BTREE:
478-
break;
479-
default:
480-
return __this_address;
481-
}
497+
fa = xfs_dinode_verify_fork(dip, mp, XFS_ATTR_FORK);
498+
if (fa)
499+
return fa;
482500
} else {
483501
/*
484502
* If there is no fork offset, this may be a freshly-made inode

fs/xfs/libxfs/xfs_rtbitmap.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,8 +1029,8 @@ xfs_rtalloc_query_range(
10291029
if (low_rec->ar_startext >= mp->m_sb.sb_rextents ||
10301030
low_rec->ar_startext == high_rec->ar_startext)
10311031
return 0;
1032-
if (high_rec->ar_startext >= mp->m_sb.sb_rextents)
1033-
high_rec->ar_startext = mp->m_sb.sb_rextents - 1;
1032+
if (high_rec->ar_startext > mp->m_sb.sb_rextents)
1033+
high_rec->ar_startext = mp->m_sb.sb_rextents;
10341034

10351035
/* Iterate the bitmap, looking for discrepancies. */
10361036
rtstart = low_rec->ar_startext;

fs/xfs/xfs_bmap_util.c

Lines changed: 52 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -685,76 +685,55 @@ xfs_getbmap(
685685
}
686686

687687
/*
688-
* dead simple method of punching delalyed allocation blocks from a range in
689-
* the inode. Walks a block at a time so will be slow, but is only executed in
690-
* rare error cases so the overhead is not critical. This will always punch out
691-
* both the start and end blocks, even if the ranges only partially overlap
692-
* them, so it is up to the caller to ensure that partial blocks are not
693-
* passed in.
688+
* Dead simple method of punching delalyed allocation blocks from a range in
689+
* the inode. This will always punch out both the start and end blocks, even
690+
* if the ranges only partially overlap them, so it is up to the caller to
691+
* ensure that partial blocks are not passed in.
694692
*/
695693
int
696694
xfs_bmap_punch_delalloc_range(
697695
struct xfs_inode *ip,
698696
xfs_fileoff_t start_fsb,
699697
xfs_fileoff_t length)
700698
{
701-
xfs_fileoff_t remaining = length;
699+
struct xfs_ifork *ifp = &ip->i_df;
700+
xfs_fileoff_t end_fsb = start_fsb + length;
701+
struct xfs_bmbt_irec got, del;
702+
struct xfs_iext_cursor icur;
702703
int error = 0;
703704

704705
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
705706

706-
do {
707-
int done;
708-
xfs_bmbt_irec_t imap;
709-
int nimaps = 1;
710-
xfs_fsblock_t firstblock;
711-
struct xfs_defer_ops dfops;
707+
if (!(ifp->if_flags & XFS_IFEXTENTS)) {
708+
error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK);
709+
if (error)
710+
return error;
711+
}
712712

713-
/*
714-
* Map the range first and check that it is a delalloc extent
715-
* before trying to unmap the range. Otherwise we will be
716-
* trying to remove a real extent (which requires a
717-
* transaction) or a hole, which is probably a bad idea...
718-
*/
719-
error = xfs_bmapi_read(ip, start_fsb, 1, &imap, &nimaps,
720-
XFS_BMAPI_ENTIRE);
713+
if (!xfs_iext_lookup_extent_before(ip, ifp, &end_fsb, &icur, &got))
714+
return 0;
721715

722-
if (error) {
723-
/* something screwed, just bail */
724-
if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
725-
xfs_alert(ip->i_mount,
726-
"Failed delalloc mapping lookup ino %lld fsb %lld.",
727-
ip->i_ino, start_fsb);
728-
}
729-
break;
730-
}
731-
if (!nimaps) {
732-
/* nothing there */
733-
goto next_block;
734-
}
735-
if (imap.br_startblock != DELAYSTARTBLOCK) {
736-
/* been converted, ignore */
737-
goto next_block;
738-
}
739-
WARN_ON(imap.br_blockcount == 0);
716+
while (got.br_startoff + got.br_blockcount > start_fsb) {
717+
del = got;
718+
xfs_trim_extent(&del, start_fsb, length);
740719

741720
/*
742-
* Note: while we initialise the firstblock/dfops pair, they
743-
* should never be used because blocks should never be
744-
* allocated or freed for a delalloc extent and hence we need
745-
* don't cancel or finish them after the xfs_bunmapi() call.
721+
* A delete can push the cursor forward. Step back to the
722+
* previous extent on non-delalloc or extents outside the
723+
* target range.
746724
*/
747-
xfs_defer_init(&dfops, &firstblock);
748-
error = xfs_bunmapi(NULL, ip, start_fsb, 1, 0, 1, &firstblock,
749-
&dfops, &done);
750-
if (error)
751-
break;
725+
if (!del.br_blockcount ||
726+
!isnullstartblock(del.br_startblock)) {
727+
if (!xfs_iext_prev_extent(ifp, &icur, &got))
728+
break;
729+
continue;
730+
}
752731

753-
ASSERT(!xfs_defer_has_unfinished_work(&dfops));
754-
next_block:
755-
start_fsb++;
756-
remaining--;
757-
} while(remaining > 0);
732+
error = xfs_bmap_del_extent_delay(ip, XFS_DATA_FORK, &icur,
733+
&got, &del);
734+
if (error || !xfs_iext_get_extent(ifp, &icur, &got))
735+
break;
736+
}
758737

759738
return error;
760739
}
@@ -1208,7 +1187,22 @@ xfs_free_file_space(
12081187
return 0;
12091188
if (offset + len > XFS_ISIZE(ip))
12101189
len = XFS_ISIZE(ip) - offset;
1211-
return iomap_zero_range(VFS_I(ip), offset, len, NULL, &xfs_iomap_ops);
1190+
error = iomap_zero_range(VFS_I(ip), offset, len, NULL, &xfs_iomap_ops);
1191+
if (error)
1192+
return error;
1193+
1194+
/*
1195+
* If we zeroed right up to EOF and EOF straddles a page boundary we
1196+
* must make sure that the post-EOF area is also zeroed because the
1197+
* page could be mmap'd and iomap_zero_range doesn't do that for us.
1198+
* Writeback of the eof page will do this, albeit clumsily.
1199+
*/
1200+
if (offset + len >= XFS_ISIZE(ip) && ((offset + len) & PAGE_MASK)) {
1201+
error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping,
1202+
(offset + len) & ~PAGE_MASK, LLONG_MAX);
1203+
}
1204+
1205+
return error;
12121206
}
12131207

12141208
/*
@@ -1404,6 +1398,10 @@ xfs_insert_file_space(
14041398

14051399
trace_xfs_insert_file_space(ip);
14061400

1401+
error = xfs_bmap_can_insert_extents(ip, stop_fsb, shift_fsb);
1402+
if (error)
1403+
return error;
1404+
14071405
error = xfs_prepare_shift(ip, offset);
14081406
if (error)
14091407
return error;

fs/xfs/xfs_fsmap.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -513,8 +513,8 @@ xfs_getfsmap_rtdev_rtbitmap_query(
513513
struct xfs_trans *tp,
514514
struct xfs_getfsmap_info *info)
515515
{
516-
struct xfs_rtalloc_rec alow;
517-
struct xfs_rtalloc_rec ahigh;
516+
struct xfs_rtalloc_rec alow = { 0 };
517+
struct xfs_rtalloc_rec ahigh = { 0 };
518518
int error;
519519

520520
xfs_ilock(tp->t_mountp->m_rbmip, XFS_ILOCK_SHARED);

fs/xfs/xfs_fsops.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ xfs_reserve_blocks(
387387
do {
388388
free = percpu_counter_sum(&mp->m_fdblocks) -
389389
mp->m_alloc_set_aside;
390-
if (!free)
390+
if (free <= 0)
391391
break;
392392

393393
delta = request - mp->m_resblks;

0 commit comments

Comments
 (0)