mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
xfs: fixes for 7.2-rc2
Signed-off-by: Carlos Maiolino <cem@kernel.org> -----BEGIN PGP SIGNATURE----- iJUEABMJAB0WIQSmtYVZ/MfVMGUq1GNcsMJ8RxYuYwUCakeeeQAKCRBcsMJ8RxYu Y6Q+AX9gnOQ1ZkxIKb+/hHq061nh/41iOaiO1CHEgvkCuX2pkRDJkIO2g5+1WaCC FcjSzLcBf0COW1/Pye2+ViB1u/SkMJZpKbrKl6lY4wcVHtqNSwn/D0zvbXsfBSsb Zj6I2kGZGw== =FpZC -----END PGP SIGNATURE----- Merge tag 'xfs-fixes-7.2-rc2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux Pull xfs fixes from Carlos Maiolino: "A collection of bugfixes and some small code refactoring" * tag 'xfs-fixes-7.2-rc2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: xfs: simplify __xfs_buf_ioend xfs: fix handling of synchronous errors in xfs_buf_submit xfs: remove xfs_buf_ioend xfs: improve the xfs_buf_ioend_fail calling convention xfs: use null daddr for unset first bad log block xfs: fix memory leak in xfs_dqinode_metadir_create() xfs: release dquot buffer after dqflush failure xfs: also mark the buffer stale on verifier failure in xfs_buf_submit xfs: open code xfs_buf_ioend_fail in xfs_buf_submit xfs: fix AGFL extent count calculation in xrep_agfl_fill xfs: simplify the failure path in xfs_buf_alloc_vmalloc xfs: fix incorrect use of gfp flags in xfs_buf_alloc_backing_mem xfs: lift setting __GFP_NOFAIL from xfs_buf_alloc_kmem to the caller xfs: split up xfs_buf_alloc_backing_mem
This commit is contained in:
commit
025d0d6221
|
|
@ -436,17 +436,27 @@ xfs_dqinode_metadir_create(
|
|||
|
||||
error = xfs_metadir_create(&upd, S_IFREG);
|
||||
if (error)
|
||||
return error;
|
||||
goto out_cancel;
|
||||
|
||||
xfs_trans_log_inode(upd.tp, upd.ip, XFS_ILOG_CORE);
|
||||
|
||||
error = xfs_metadir_commit(&upd);
|
||||
if (error)
|
||||
return error;
|
||||
goto out_irele;
|
||||
|
||||
xfs_finish_inode_setup(upd.ip);
|
||||
*ipp = upd.ip;
|
||||
return 0;
|
||||
|
||||
out_cancel:
|
||||
xfs_metadir_cancel(&upd, error);
|
||||
out_irele:
|
||||
/* Have to finish setting up the inode to ensure it's deleted. */
|
||||
if (upd.ip) {
|
||||
xfs_finish_inode_setup(upd.ip);
|
||||
xfs_irele(upd.ip);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
#ifndef __KERNEL__
|
||||
|
|
|
|||
|
|
@ -652,7 +652,7 @@ xrep_agfl_fill(
|
|||
while (agbno < start + len && af->fl_off < af->flcount)
|
||||
af->agfl_bno[af->fl_off++] = cpu_to_be32(agbno++);
|
||||
|
||||
error = xagb_bitmap_set(&af->used_extents, start, agbno - 1);
|
||||
error = xagb_bitmap_set(&af->used_extents, start, agbno - start);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
|
|
|||
190
fs/xfs/xfs_buf.c
190
fs/xfs/xfs_buf.c
|
|
@ -120,6 +120,22 @@ xfs_buf_free(
|
|||
call_rcu(&bp->b_rcu, xfs_buf_free_callback);
|
||||
}
|
||||
|
||||
static int
|
||||
xfs_buf_alloc_folio(
|
||||
struct xfs_buf *bp,
|
||||
size_t size,
|
||||
gfp_t gfp_mask)
|
||||
{
|
||||
struct folio *folio;
|
||||
|
||||
folio = folio_alloc(gfp_mask, get_order(size));
|
||||
if (!folio)
|
||||
return -ENOMEM;
|
||||
bp->b_addr = folio_address(folio);
|
||||
trace_xfs_buf_backing_folio(bp, _RET_IP_);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
xfs_buf_alloc_kmem(
|
||||
struct xfs_buf *bp,
|
||||
|
|
@ -129,7 +145,7 @@ xfs_buf_alloc_kmem(
|
|||
ASSERT(is_power_of_2(size));
|
||||
ASSERT(size < PAGE_SIZE);
|
||||
|
||||
bp->b_addr = kmalloc(size, gfp_mask | __GFP_NOFAIL);
|
||||
bp->b_addr = kmalloc(size, gfp_mask);
|
||||
if (!bp->b_addr)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -148,6 +164,26 @@ xfs_buf_alloc_kmem(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
xfs_buf_alloc_vmalloc(
|
||||
struct xfs_buf *bp,
|
||||
size_t size,
|
||||
gfp_t gfp_mask)
|
||||
{
|
||||
for (;;) {
|
||||
bp->b_addr = __vmalloc(size, gfp_mask);
|
||||
if (bp->b_addr)
|
||||
break;
|
||||
if (gfp_mask & __GFP_NORETRY)
|
||||
return -ENOMEM;
|
||||
XFS_STATS_INC(bp->b_mount, xb_page_retries);
|
||||
memalloc_retry_wait(gfp_mask);
|
||||
}
|
||||
|
||||
trace_xfs_buf_backing_vmalloc(bp, _RET_IP_);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate backing memory for a buffer.
|
||||
*
|
||||
|
|
@ -175,7 +211,6 @@ xfs_buf_alloc_backing_mem(
|
|||
{
|
||||
size_t size = BBTOB(bp->b_length);
|
||||
gfp_t gfp_mask = GFP_KERNEL | __GFP_NOLOCKDEP | __GFP_NOWARN;
|
||||
struct folio *folio;
|
||||
|
||||
if (xfs_buftarg_is_mem(bp->b_target))
|
||||
return xmbuf_map_backing_mem(bp);
|
||||
|
|
@ -187,22 +222,6 @@ xfs_buf_alloc_backing_mem(
|
|||
if (flags & XBF_READ_AHEAD)
|
||||
gfp_mask |= __GFP_NORETRY;
|
||||
|
||||
/*
|
||||
* For buffers smaller than PAGE_SIZE use a kmalloc allocation if that
|
||||
* is properly aligned. The slab allocator now guarantees an aligned
|
||||
* allocation for all power of two sizes, which matches most of the
|
||||
* smaller than PAGE_SIZE buffers used by XFS.
|
||||
*/
|
||||
if (size < PAGE_SIZE && is_power_of_2(size))
|
||||
return xfs_buf_alloc_kmem(bp, size, gfp_mask);
|
||||
|
||||
/*
|
||||
* Don't bother with the retry loop for single PAGE allocations: vmalloc
|
||||
* won't do any better.
|
||||
*/
|
||||
if (size <= PAGE_SIZE)
|
||||
gfp_mask |= __GFP_NOFAIL;
|
||||
|
||||
/*
|
||||
* Optimistically attempt a single high order folio allocation for
|
||||
* larger than PAGE_SIZE buffers.
|
||||
|
|
@ -215,35 +234,31 @@ xfs_buf_alloc_backing_mem(
|
|||
* path for them instead of wasting memory here.
|
||||
*/
|
||||
if (size > PAGE_SIZE) {
|
||||
if (!is_power_of_2(size))
|
||||
goto fallback;
|
||||
gfp_mask &= ~__GFP_DIRECT_RECLAIM;
|
||||
gfp_mask |= __GFP_NORETRY;
|
||||
}
|
||||
folio = folio_alloc(gfp_mask, get_order(size));
|
||||
if (!folio) {
|
||||
if (size <= PAGE_SIZE)
|
||||
return -ENOMEM;
|
||||
trace_xfs_buf_backing_fallback(bp, _RET_IP_);
|
||||
goto fallback;
|
||||
}
|
||||
bp->b_addr = folio_address(folio);
|
||||
trace_xfs_buf_backing_folio(bp, _RET_IP_);
|
||||
return 0;
|
||||
if (is_power_of_2(size)) {
|
||||
gfp_t folio_gfp = gfp_mask;
|
||||
|
||||
fallback:
|
||||
for (;;) {
|
||||
bp->b_addr = __vmalloc(size, gfp_mask);
|
||||
if (bp->b_addr)
|
||||
break;
|
||||
if (flags & XBF_READ_AHEAD)
|
||||
return -ENOMEM;
|
||||
XFS_STATS_INC(bp->b_mount, xb_page_retries);
|
||||
memalloc_retry_wait(gfp_mask);
|
||||
folio_gfp &= ~__GFP_DIRECT_RECLAIM;
|
||||
folio_gfp |= __GFP_NORETRY;
|
||||
if (xfs_buf_alloc_folio(bp, size, folio_gfp) == 0)
|
||||
return 0;
|
||||
trace_xfs_buf_backing_fallback(bp, _RET_IP_);
|
||||
}
|
||||
return xfs_buf_alloc_vmalloc(bp, size, gfp_mask);
|
||||
}
|
||||
|
||||
trace_xfs_buf_backing_vmalloc(bp, _RET_IP_);
|
||||
return 0;
|
||||
/*
|
||||
* The slab allocator now guarantees aligned allocations for all power
|
||||
* of two sizes. This covers most smaller XFS buffers, so just use
|
||||
* kmalloc in this case.
|
||||
*
|
||||
* Don't bother with the vmalloc fallback for allocations of page size
|
||||
* or less: vmalloc won't do any better.
|
||||
*/
|
||||
if (!(gfp_mask & __GFP_NORETRY))
|
||||
gfp_mask |= __GFP_NOFAIL;
|
||||
if (size < PAGE_SIZE && is_power_of_2(size))
|
||||
return xfs_buf_alloc_kmem(bp, size, gfp_mask);
|
||||
return xfs_buf_alloc_folio(bp, size, gfp_mask);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -1083,11 +1098,17 @@ xfs_buf_ioend_handle_error(
|
|||
return false;
|
||||
}
|
||||
|
||||
/* returns false if the caller needs to resubmit the I/O, else true */
|
||||
static bool
|
||||
__xfs_buf_ioend(
|
||||
/*
|
||||
* Complete a buffer read or write.
|
||||
*
|
||||
* Releases the buffer if the I/O was asynchronous.
|
||||
*/
|
||||
static void
|
||||
xfs_buf_ioend(
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
bool async = bp->b_flags & XBF_ASYNC;
|
||||
|
||||
trace_xfs_buf_iodone(bp, _RET_IP_);
|
||||
|
||||
if (bp->b_flags & XBF_READ) {
|
||||
|
|
@ -1101,14 +1122,16 @@ __xfs_buf_ioend(
|
|||
if (bp->b_flags & XBF_READ_AHEAD)
|
||||
percpu_counter_dec(&bp->b_target->bt_readahead_count);
|
||||
} else {
|
||||
if (!bp->b_error) {
|
||||
if (unlikely(bp->b_error)) {
|
||||
if (xfs_buf_ioend_handle_error(bp)) {
|
||||
ASSERT(async);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
bp->b_flags &= ~XBF_WRITE_FAIL;
|
||||
bp->b_flags |= XBF_DONE;
|
||||
}
|
||||
|
||||
if (unlikely(bp->b_error) && xfs_buf_ioend_handle_error(bp))
|
||||
return false;
|
||||
|
||||
/* clear the retry state */
|
||||
bp->b_last_error = 0;
|
||||
bp->b_retries = 0;
|
||||
|
|
@ -1128,30 +1151,15 @@ __xfs_buf_ioend(
|
|||
|
||||
bp->b_flags &= ~(XBF_READ | XBF_WRITE | XBF_READ_AHEAD |
|
||||
_XBF_LOGRECOVERY);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_buf_ioend(
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
if (!__xfs_buf_ioend(bp))
|
||||
return;
|
||||
if (bp->b_flags & XBF_ASYNC)
|
||||
if (async)
|
||||
xfs_buf_relse(bp);
|
||||
else
|
||||
complete(&bp->b_iowait);
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_buf_ioend_work(
|
||||
struct work_struct *work)
|
||||
{
|
||||
struct xfs_buf *bp =
|
||||
container_of(work, struct xfs_buf, b_ioend_work);
|
||||
|
||||
if (__xfs_buf_ioend(bp))
|
||||
xfs_buf_relse(bp);
|
||||
xfs_buf_ioend(container_of(work, struct xfs_buf, b_ioend_work));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1177,17 +1185,18 @@ xfs_buf_ioerror_alert(
|
|||
}
|
||||
|
||||
/*
|
||||
* To simulate an I/O failure, the buffer must be locked and held with at least
|
||||
* two references.
|
||||
* Fail a locked and referenced buffer outside the I/O path.
|
||||
*
|
||||
* The buf item reference is dropped via ioend processing. The second reference
|
||||
* is owned by the caller and is dropped on I/O completion if the buffer is
|
||||
* XBF_ASYNC.
|
||||
* The caller transfers a reference which will be released after processing the
|
||||
* error.
|
||||
*/
|
||||
void
|
||||
xfs_buf_ioend_fail(
|
||||
xfs_buf_fail(
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
ASSERT(xfs_buf_islocked(bp));
|
||||
|
||||
bp->b_flags |= XBF_ASYNC;
|
||||
bp->b_flags &= ~XBF_DONE;
|
||||
xfs_buf_stale(bp);
|
||||
xfs_buf_ioerror(bp, -EIO);
|
||||
|
|
@ -1300,12 +1309,11 @@ xfs_buf_iowait(
|
|||
{
|
||||
ASSERT(!(bp->b_flags & XBF_ASYNC));
|
||||
|
||||
do {
|
||||
trace_xfs_buf_iowait(bp, _RET_IP_);
|
||||
wait_for_completion(&bp->b_iowait);
|
||||
trace_xfs_buf_iowait_done(bp, _RET_IP_);
|
||||
} while (!__xfs_buf_ioend(bp));
|
||||
trace_xfs_buf_iowait(bp, _RET_IP_);
|
||||
wait_for_completion(&bp->b_iowait);
|
||||
trace_xfs_buf_iowait_done(bp, _RET_IP_);
|
||||
|
||||
xfs_buf_ioend(bp);
|
||||
return bp->b_error;
|
||||
}
|
||||
|
||||
|
|
@ -1369,8 +1377,8 @@ xfs_buf_submit(
|
|||
* on shutdown.
|
||||
*/
|
||||
if (bp->b_mount->m_log && xlog_is_shutdown(bp->b_mount->m_log)) {
|
||||
xfs_buf_ioend_fail(bp);
|
||||
return;
|
||||
xfs_buf_ioerror(bp, -EIO);
|
||||
goto ioerror;
|
||||
}
|
||||
|
||||
if (bp->b_flags & XBF_WRITE)
|
||||
|
|
@ -1383,18 +1391,26 @@ xfs_buf_submit(
|
|||
bp->b_error = 0;
|
||||
|
||||
if ((bp->b_flags & XBF_WRITE) && !xfs_buf_verify_write(bp)) {
|
||||
/* ->verify_write should have set b_error already */
|
||||
xfs_force_shutdown(bp->b_mount, SHUTDOWN_CORRUPT_INCORE);
|
||||
xfs_buf_ioend(bp);
|
||||
return;
|
||||
goto ioerror;
|
||||
}
|
||||
|
||||
/* In-memory targets are directly mapped, no I/O required. */
|
||||
if (xfs_buftarg_is_mem(bp->b_target)) {
|
||||
xfs_buf_ioend(bp);
|
||||
return;
|
||||
}
|
||||
if (xfs_buftarg_is_mem(bp->b_target))
|
||||
goto end_io;
|
||||
|
||||
xfs_buf_submit_bio(bp);
|
||||
return;
|
||||
|
||||
ioerror:
|
||||
bp->b_flags &= ~XBF_DONE;
|
||||
xfs_buf_stale(bp);
|
||||
end_io:
|
||||
if (bp->b_flags & XBF_ASYNC)
|
||||
xfs_buf_ioend(bp);
|
||||
else
|
||||
complete(&bp->b_iowait);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ extern void __xfs_buf_ioerror(struct xfs_buf *bp, int error,
|
|||
xfs_failaddr_t failaddr);
|
||||
#define xfs_buf_ioerror(bp, err) __xfs_buf_ioerror((bp), (err), __this_address)
|
||||
extern void xfs_buf_ioerror_alert(struct xfs_buf *bp, xfs_failaddr_t fa);
|
||||
void xfs_buf_ioend_fail(struct xfs_buf *);
|
||||
void xfs_buf_fail(struct xfs_buf *bp);
|
||||
void __xfs_buf_mark_corrupt(struct xfs_buf *bp, xfs_failaddr_t fa);
|
||||
#define xfs_buf_mark_corrupt(bp) __xfs_buf_mark_corrupt((bp), __this_address)
|
||||
|
||||
|
|
|
|||
|
|
@ -549,8 +549,7 @@ xfs_buf_item_unpin(
|
|||
* wait for the lock and then run the IO failure completion.
|
||||
*/
|
||||
xfs_buf_lock(bp);
|
||||
bp->b_flags |= XBF_ASYNC;
|
||||
xfs_buf_ioend_fail(bp);
|
||||
xfs_buf_fail(bp);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2646,8 +2646,7 @@ xfs_iflush_cluster(
|
|||
* inode cluster buffers.
|
||||
*/
|
||||
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
|
||||
bp->b_flags |= XBF_ASYNC;
|
||||
xfs_buf_ioend_fail(bp);
|
||||
xfs_buf_fail(bp);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1028,7 +1028,7 @@ xlog_verify_head(
|
|||
{
|
||||
struct xlog_rec_header *tmp_rhead;
|
||||
char *tmp_buffer;
|
||||
xfs_daddr_t first_bad;
|
||||
xfs_daddr_t first_bad = XFS_BUF_DADDR_NULL;
|
||||
xfs_daddr_t tmp_rhead_blk;
|
||||
int found;
|
||||
int error;
|
||||
|
|
@ -1057,7 +1057,8 @@ xlog_verify_head(
|
|||
*/
|
||||
error = xlog_do_recovery_pass(log, *head_blk, tmp_rhead_blk,
|
||||
XLOG_RECOVER_CRCPASS, &first_bad);
|
||||
if ((error == -EFSBADCRC || error == -EFSCORRUPTED) && first_bad) {
|
||||
if ((error == -EFSBADCRC || error == -EFSCORRUPTED) &&
|
||||
first_bad != XFS_BUF_DADDR_NULL) {
|
||||
/*
|
||||
* We've hit a potential torn write. Reset the error and warn
|
||||
* about it.
|
||||
|
|
@ -3575,4 +3576,3 @@ xlog_recover_cancel(
|
|||
if (xlog_recovery_needed(log))
|
||||
xlog_recover_cancel_intents(log);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -166,10 +166,9 @@ xfs_qm_dqpurge(
|
|||
* does it on success.
|
||||
*/
|
||||
error = xfs_qm_dqflush(dqp, bp);
|
||||
if (!error) {
|
||||
if (!error)
|
||||
error = xfs_bwrite(bp);
|
||||
xfs_buf_relse(bp);
|
||||
}
|
||||
xfs_buf_relse(bp);
|
||||
xfs_dqflock(dqp);
|
||||
}
|
||||
xfs_dquot_detach_buf(dqp);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user