Skip to content

Commit 9872e4a

Browse files
committed
Merge tag 'xfs-5.20-merge-8' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
Pull more xfs updates from Darrick Wong: "There's not a lot this time around, just the usual bug fixes and corrections for missing error returns. - Return error codes from block device flushes to userspace - Fix a deadlock between reclaim and mount time quotacheck - Fix an unnecessary ENOSPC return when doing COW on a filesystem with severe free space fragmentation - Fix a miscalculation in the transaction reservation computations for file removal operations" * tag 'xfs-5.20-merge-8' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: xfs: fix inode reservation space for removing transaction xfs: Fix false ENOSPC when performing direct write on a delalloc extent in cow fork xfs: fix intermittent hang during quotacheck xfs: check return codes when flushing block devices
2 parents e140f73 + 031d166 commit 9872e4a

File tree

5 files changed

+193
-46
lines changed

5 files changed

+193
-46
lines changed

fs/xfs/libxfs/xfs_trans_resv.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ xfs_calc_remove_reservation(
515515
{
516516
return XFS_DQUOT_LOGRES(mp) +
517517
xfs_calc_iunlink_add_reservation(mp) +
518-
max((xfs_calc_inode_res(mp, 1) +
518+
max((xfs_calc_inode_res(mp, 2) +
519519
xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
520520
XFS_FSB_TO_B(mp, 1))),
521521
(xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) +

fs/xfs/xfs_file.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ xfs_file_fsync(
143143
{
144144
struct xfs_inode *ip = XFS_I(file->f_mapping->host);
145145
struct xfs_mount *mp = ip->i_mount;
146-
int error = 0;
146+
int error, err2;
147147
int log_flushed = 0;
148148

149149
trace_xfs_file_fsync(ip);
@@ -164,18 +164,21 @@ xfs_file_fsync(
164164
* inode size in case of an extending write.
165165
*/
166166
if (XFS_IS_REALTIME_INODE(ip))
167-
blkdev_issue_flush(mp->m_rtdev_targp->bt_bdev);
167+
error = blkdev_issue_flush(mp->m_rtdev_targp->bt_bdev);
168168
else if (mp->m_logdev_targp != mp->m_ddev_targp)
169-
blkdev_issue_flush(mp->m_ddev_targp->bt_bdev);
169+
error = blkdev_issue_flush(mp->m_ddev_targp->bt_bdev);
170170

171171
/*
172172
* Any inode that has dirty modifications in the log is pinned. The
173-
* racy check here for a pinned inode while not catch modifications
173+
* racy check here for a pinned inode will not catch modifications
174174
* that happen concurrently to the fsync call, but fsync semantics
175175
* only require to sync previously completed I/O.
176176
*/
177-
if (xfs_ipincount(ip))
178-
error = xfs_fsync_flush_log(ip, datasync, &log_flushed);
177+
if (xfs_ipincount(ip)) {
178+
err2 = xfs_fsync_flush_log(ip, datasync, &log_flushed);
179+
if (err2 && !error)
180+
error = err2;
181+
}
179182

180183
/*
181184
* If we only have a single device, and the log force about was
@@ -185,8 +188,11 @@ xfs_file_fsync(
185188
* commit.
186189
*/
187190
if (!log_flushed && !XFS_IS_REALTIME_INODE(ip) &&
188-
mp->m_logdev_targp == mp->m_ddev_targp)
189-
blkdev_issue_flush(mp->m_ddev_targp->bt_bdev);
191+
mp->m_logdev_targp == mp->m_ddev_targp) {
192+
err2 = blkdev_issue_flush(mp->m_ddev_targp->bt_bdev);
193+
if (err2 && !error)
194+
error = err2;
195+
}
190196

191197
return error;
192198
}

fs/xfs/xfs_log.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1925,9 +1925,17 @@ xlog_write_iclog(
19251925
* device cache first to ensure all metadata writeback covered
19261926
* by the LSN in this iclog is on stable storage. This is slow,
19271927
* but it *must* complete before we issue the external log IO.
1928+
*
1929+
* If the flush fails, we cannot conclude that past metadata
1930+
* writeback from the log succeeded. Repeating the flush is
1931+
* not possible, hence we must shut down with log IO error to
1932+
* avoid shutdown re-entering this path and erroring out again.
19281933
*/
1929-
if (log->l_targ != log->l_mp->m_ddev_targp)
1930-
blkdev_issue_flush(log->l_mp->m_ddev_targp->bt_bdev);
1934+
if (log->l_targ != log->l_mp->m_ddev_targp &&
1935+
blkdev_issue_flush(log->l_mp->m_ddev_targp->bt_bdev)) {
1936+
xlog_force_shutdown(log, SHUTDOWN_LOG_IO_ERROR);
1937+
return;
1938+
}
19311939
}
19321940
if (iclog->ic_flags & XLOG_ICL_NEED_FUA)
19331941
iclog->ic_bio.bi_opf |= REQ_FUA;

fs/xfs/xfs_qm.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,6 +1235,11 @@ xfs_qm_flush_one(
12351235
if (error)
12361236
goto out_unlock;
12371237

1238+
if (!(bp->b_flags & _XBF_DELWRI_Q)) {
1239+
error = -EAGAIN;
1240+
xfs_buf_relse(bp);
1241+
goto out_unlock;
1242+
}
12381243
xfs_buf_unlock(bp);
12391244

12401245
xfs_buf_delwri_pushbuf(bp, buffer_list);

fs/xfs/xfs_reflink.c

Lines changed: 163 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -341,9 +341,41 @@ xfs_find_trim_cow_extent(
341341
return 0;
342342
}
343343

344-
/* Allocate all CoW reservations covering a range of blocks in a file. */
345-
int
346-
xfs_reflink_allocate_cow(
344+
static int
345+
xfs_reflink_convert_unwritten(
346+
struct xfs_inode *ip,
347+
struct xfs_bmbt_irec *imap,
348+
struct xfs_bmbt_irec *cmap,
349+
bool convert_now)
350+
{
351+
xfs_fileoff_t offset_fsb = imap->br_startoff;
352+
xfs_filblks_t count_fsb = imap->br_blockcount;
353+
int error;
354+
355+
/*
356+
* cmap might larger than imap due to cowextsize hint.
357+
*/
358+
xfs_trim_extent(cmap, offset_fsb, count_fsb);
359+
360+
/*
361+
* COW fork extents are supposed to remain unwritten until we're ready
362+
* to initiate a disk write. For direct I/O we are going to write the
363+
* data and need the conversion, but for buffered writes we're done.
364+
*/
365+
if (!convert_now || cmap->br_state == XFS_EXT_NORM)
366+
return 0;
367+
368+
trace_xfs_reflink_convert_cow(ip, cmap);
369+
370+
error = xfs_reflink_convert_cow_locked(ip, offset_fsb, count_fsb);
371+
if (!error)
372+
cmap->br_state = XFS_EXT_NORM;
373+
374+
return error;
375+
}
376+
377+
static int
378+
xfs_reflink_fill_cow_hole(
347379
struct xfs_inode *ip,
348380
struct xfs_bmbt_irec *imap,
349381
struct xfs_bmbt_irec *cmap,
@@ -352,25 +384,12 @@ xfs_reflink_allocate_cow(
352384
bool convert_now)
353385
{
354386
struct xfs_mount *mp = ip->i_mount;
355-
xfs_fileoff_t offset_fsb = imap->br_startoff;
356-
xfs_filblks_t count_fsb = imap->br_blockcount;
357387
struct xfs_trans *tp;
358-
int nimaps, error = 0;
359-
bool found;
360388
xfs_filblks_t resaligned;
361-
xfs_extlen_t resblks = 0;
362-
363-
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
364-
if (!ip->i_cowfp) {
365-
ASSERT(!xfs_is_reflink_inode(ip));
366-
xfs_ifork_init_cow(ip);
367-
}
368-
369-
error = xfs_find_trim_cow_extent(ip, imap, cmap, shared, &found);
370-
if (error || !*shared)
371-
return error;
372-
if (found)
373-
goto convert;
389+
xfs_extlen_t resblks;
390+
int nimaps;
391+
int error;
392+
bool found;
374393

375394
resaligned = xfs_aligned_fsb_count(imap->br_startoff,
376395
imap->br_blockcount, xfs_get_cowextsz_hint(ip));
@@ -386,17 +405,17 @@ xfs_reflink_allocate_cow(
386405

387406
*lockmode = XFS_ILOCK_EXCL;
388407

389-
/*
390-
* Check for an overlapping extent again now that we dropped the ilock.
391-
*/
392408
error = xfs_find_trim_cow_extent(ip, imap, cmap, shared, &found);
393409
if (error || !*shared)
394410
goto out_trans_cancel;
411+
395412
if (found) {
396413
xfs_trans_cancel(tp);
397414
goto convert;
398415
}
399416

417+
ASSERT(cmap->br_startoff > imap->br_startoff);
418+
400419
/* Allocate the entire reservation as unwritten blocks. */
401420
nimaps = 1;
402421
error = xfs_bmapi_write(tp, ip, imap->br_startoff, imap->br_blockcount,
@@ -416,26 +435,135 @@ xfs_reflink_allocate_cow(
416435
*/
417436
if (nimaps == 0)
418437
return -ENOSPC;
438+
419439
convert:
420-
xfs_trim_extent(cmap, offset_fsb, count_fsb);
421-
/*
422-
* COW fork extents are supposed to remain unwritten until we're ready
423-
* to initiate a disk write. For direct I/O we are going to write the
424-
* data and need the conversion, but for buffered writes we're done.
425-
*/
426-
if (!convert_now || cmap->br_state == XFS_EXT_NORM)
427-
return 0;
428-
trace_xfs_reflink_convert_cow(ip, cmap);
429-
error = xfs_reflink_convert_cow_locked(ip, offset_fsb, count_fsb);
430-
if (!error)
431-
cmap->br_state = XFS_EXT_NORM;
440+
return xfs_reflink_convert_unwritten(ip, imap, cmap, convert_now);
441+
442+
out_trans_cancel:
443+
xfs_trans_cancel(tp);
432444
return error;
445+
}
446+
447+
static int
448+
xfs_reflink_fill_delalloc(
449+
struct xfs_inode *ip,
450+
struct xfs_bmbt_irec *imap,
451+
struct xfs_bmbt_irec *cmap,
452+
bool *shared,
453+
uint *lockmode,
454+
bool convert_now)
455+
{
456+
struct xfs_mount *mp = ip->i_mount;
457+
struct xfs_trans *tp;
458+
int nimaps;
459+
int error;
460+
bool found;
461+
462+
do {
463+
xfs_iunlock(ip, *lockmode);
464+
*lockmode = 0;
465+
466+
error = xfs_trans_alloc_inode(ip, &M_RES(mp)->tr_write, 0, 0,
467+
false, &tp);
468+
if (error)
469+
return error;
470+
471+
*lockmode = XFS_ILOCK_EXCL;
472+
473+
error = xfs_find_trim_cow_extent(ip, imap, cmap, shared,
474+
&found);
475+
if (error || !*shared)
476+
goto out_trans_cancel;
477+
478+
if (found) {
479+
xfs_trans_cancel(tp);
480+
break;
481+
}
482+
483+
ASSERT(isnullstartblock(cmap->br_startblock) ||
484+
cmap->br_startblock == DELAYSTARTBLOCK);
485+
486+
/*
487+
* Replace delalloc reservation with an unwritten extent.
488+
*/
489+
nimaps = 1;
490+
error = xfs_bmapi_write(tp, ip, cmap->br_startoff,
491+
cmap->br_blockcount,
492+
XFS_BMAPI_COWFORK | XFS_BMAPI_PREALLOC, 0,
493+
cmap, &nimaps);
494+
if (error)
495+
goto out_trans_cancel;
496+
497+
xfs_inode_set_cowblocks_tag(ip);
498+
error = xfs_trans_commit(tp);
499+
if (error)
500+
return error;
501+
502+
/*
503+
* Allocation succeeded but the requested range was not even
504+
* partially satisfied? Bail out!
505+
*/
506+
if (nimaps == 0)
507+
return -ENOSPC;
508+
} while (cmap->br_startoff + cmap->br_blockcount <= imap->br_startoff);
509+
510+
return xfs_reflink_convert_unwritten(ip, imap, cmap, convert_now);
433511

434512
out_trans_cancel:
435513
xfs_trans_cancel(tp);
436514
return error;
437515
}
438516

517+
/* Allocate all CoW reservations covering a range of blocks in a file. */
518+
int
519+
xfs_reflink_allocate_cow(
520+
struct xfs_inode *ip,
521+
struct xfs_bmbt_irec *imap,
522+
struct xfs_bmbt_irec *cmap,
523+
bool *shared,
524+
uint *lockmode,
525+
bool convert_now)
526+
{
527+
int error;
528+
bool found;
529+
530+
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
531+
if (!ip->i_cowfp) {
532+
ASSERT(!xfs_is_reflink_inode(ip));
533+
xfs_ifork_init_cow(ip);
534+
}
535+
536+
error = xfs_find_trim_cow_extent(ip, imap, cmap, shared, &found);
537+
if (error || !*shared)
538+
return error;
539+
540+
/* CoW fork has a real extent */
541+
if (found)
542+
return xfs_reflink_convert_unwritten(ip, imap, cmap,
543+
convert_now);
544+
545+
/*
546+
* CoW fork does not have an extent and data extent is shared.
547+
* Allocate a real extent in the CoW fork.
548+
*/
549+
if (cmap->br_startoff > imap->br_startoff)
550+
return xfs_reflink_fill_cow_hole(ip, imap, cmap, shared,
551+
lockmode, convert_now);
552+
553+
/*
554+
* CoW fork has a delalloc reservation. Replace it with a real extent.
555+
* There may or may not be a data fork mapping.
556+
*/
557+
if (isnullstartblock(cmap->br_startblock) ||
558+
cmap->br_startblock == DELAYSTARTBLOCK)
559+
return xfs_reflink_fill_delalloc(ip, imap, cmap, shared,
560+
lockmode, convert_now);
561+
562+
/* Shouldn't get here. */
563+
ASSERT(0);
564+
return -EFSCORRUPTED;
565+
}
566+
439567
/*
440568
* Cancel CoW reservations for some block range of an inode.
441569
*

0 commit comments

Comments
 (0)