Skip to content

Commit 788c1da

Browse files
committed
Merge tag 'xfs-4.15-fixes-4' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
Pull xfs fixes from Darrick Wong: "Here are some bug fixes for 4.15-rc2. - fix memory leaks that appeared after removing ifork inline data buffer - recover deferred rmap update log items in correct order - fix memory leaks when buffer construction fails - fix memory leaks when bmbt is corrupt - fix some uninitialized variables and math problems in the quota scrubber - add some omitted attribution tags on the log replay commit - fix some UBSAN complaints about integer overflows with large sparse files - implement an effective inode mode check in online fsck - fix log's inability to retry quota item writeout due to transient errors" * tag 'xfs-4.15-fixes-4' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: xfs: Properly retry failed dquot items in case of error during buffer writeback xfs: scrub inode mode properly xfs: remove unused parameter from xfs_writepage_map xfs: ubsan fixes xfs: calculate correct offset in xfs_scrub_quota_item xfs: fix uninitialized variable in xfs_scrub_quota xfs: fix leaks on corruption errors in xfs_bmap.c xfs: fortify xfs_alloc_buftarg error handling xfs: log recovery should replay deferred ops in order xfs: always free inline data before resetting inode fork during ifree
2 parents e1ba1c9 + 373b058 commit 788c1da

13 files changed

+190
-61
lines changed

fs/xfs/libxfs/xfs_bmap.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5662,7 +5662,8 @@ xfs_bmap_collapse_extents(
56625662
*done = true;
56635663
goto del_cursor;
56645664
}
5665-
XFS_WANT_CORRUPTED_RETURN(mp, !isnullstartblock(got.br_startblock));
5665+
XFS_WANT_CORRUPTED_GOTO(mp, !isnullstartblock(got.br_startblock),
5666+
del_cursor);
56665667

56675668
new_startoff = got.br_startoff - offset_shift_fsb;
56685669
if (xfs_iext_peek_prev_extent(ifp, &icur, &prev)) {
@@ -5767,7 +5768,8 @@ xfs_bmap_insert_extents(
57675768
goto del_cursor;
57685769
}
57695770
}
5770-
XFS_WANT_CORRUPTED_RETURN(mp, !isnullstartblock(got.br_startblock));
5771+
XFS_WANT_CORRUPTED_GOTO(mp, !isnullstartblock(got.br_startblock),
5772+
del_cursor);
57715773

57725774
if (stop_fsb >= got.br_startoff + got.br_blockcount) {
57735775
error = -EIO;

fs/xfs/scrub/inode.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,8 +318,20 @@ xfs_scrub_dinode(
318318

319319
/* di_mode */
320320
mode = be16_to_cpu(dip->di_mode);
321-
if (mode & ~(S_IALLUGO | S_IFMT))
321+
switch (mode & S_IFMT) {
322+
case S_IFLNK:
323+
case S_IFREG:
324+
case S_IFDIR:
325+
case S_IFCHR:
326+
case S_IFBLK:
327+
case S_IFIFO:
328+
case S_IFSOCK:
329+
/* mode is recognized */
330+
break;
331+
default:
322332
xfs_scrub_ino_set_corrupt(sc, ino, bp);
333+
break;
334+
}
323335

324336
/* v1/v2 fields */
325337
switch (dip->di_version) {

fs/xfs/scrub/quota.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ xfs_scrub_quota_item(
107107
unsigned long long rcount;
108108
xfs_ino_t fs_icount;
109109

110-
offset = id * qi->qi_dqperchunk;
110+
offset = id / qi->qi_dqperchunk;
111111

112112
/*
113113
* We fed $id and DQNEXT into the xfs_qm_dqget call, which means
@@ -207,7 +207,7 @@ xfs_scrub_quota(
207207
xfs_dqid_t id = 0;
208208
uint dqtype;
209209
int nimaps;
210-
int error;
210+
int error = 0;
211211

212212
if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
213213
return -ENOENT;

fs/xfs/xfs_aops.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ xfs_map_blocks(
399399
(ip->i_df.if_flags & XFS_IFEXTENTS));
400400
ASSERT(offset <= mp->m_super->s_maxbytes);
401401

402-
if (offset + count > mp->m_super->s_maxbytes)
402+
if ((xfs_ufsize_t)offset + count > mp->m_super->s_maxbytes)
403403
count = mp->m_super->s_maxbytes - offset;
404404
end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count);
405405
offset_fsb = XFS_B_TO_FSBT(mp, offset);
@@ -896,13 +896,13 @@ xfs_writepage_map(
896896
struct writeback_control *wbc,
897897
struct inode *inode,
898898
struct page *page,
899-
loff_t offset,
900-
uint64_t end_offset)
899+
uint64_t end_offset)
901900
{
902901
LIST_HEAD(submit_list);
903902
struct xfs_ioend *ioend, *next;
904903
struct buffer_head *bh, *head;
905904
ssize_t len = i_blocksize(inode);
905+
uint64_t offset;
906906
int error = 0;
907907
int count = 0;
908908
int uptodate = 1;
@@ -1146,7 +1146,7 @@ xfs_do_writepage(
11461146
end_offset = offset;
11471147
}
11481148

1149-
return xfs_writepage_map(wpc, wbc, inode, page, offset, end_offset);
1149+
return xfs_writepage_map(wpc, wbc, inode, page, end_offset);
11501150

11511151
redirty:
11521152
redirty_page_for_writepage(wbc, page);
@@ -1265,7 +1265,7 @@ xfs_map_trim_size(
12651265
if (mapping_size > size)
12661266
mapping_size = size;
12671267
if (offset < i_size_read(inode) &&
1268-
offset + mapping_size >= i_size_read(inode)) {
1268+
(xfs_ufsize_t)offset + mapping_size >= i_size_read(inode)) {
12691269
/* limit mapping to block that spans EOF */
12701270
mapping_size = roundup_64(i_size_read(inode) - offset,
12711271
i_blocksize(inode));
@@ -1312,7 +1312,7 @@ xfs_get_blocks(
13121312
lockmode = xfs_ilock_data_map_shared(ip);
13131313

13141314
ASSERT(offset <= mp->m_super->s_maxbytes);
1315-
if (offset + size > mp->m_super->s_maxbytes)
1315+
if ((xfs_ufsize_t)offset + size > mp->m_super->s_maxbytes)
13161316
size = mp->m_super->s_maxbytes - offset;
13171317
end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + size);
13181318
offset_fsb = XFS_B_TO_FSBT(mp, offset);

fs/xfs/xfs_bmap_item.c

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,8 @@ xfs_bud_init(
389389
int
390390
xfs_bui_recover(
391391
struct xfs_mount *mp,
392-
struct xfs_bui_log_item *buip)
392+
struct xfs_bui_log_item *buip,
393+
struct xfs_defer_ops *dfops)
393394
{
394395
int error = 0;
395396
unsigned int bui_type;
@@ -404,9 +405,7 @@ xfs_bui_recover(
404405
xfs_exntst_t state;
405406
struct xfs_trans *tp;
406407
struct xfs_inode *ip = NULL;
407-
struct xfs_defer_ops dfops;
408408
struct xfs_bmbt_irec irec;
409-
xfs_fsblock_t firstfsb;
410409

411410
ASSERT(!test_bit(XFS_BUI_RECOVERED, &buip->bui_flags));
412411

@@ -464,7 +463,6 @@ xfs_bui_recover(
464463

465464
if (VFS_I(ip)->i_nlink == 0)
466465
xfs_iflags_set(ip, XFS_IRECOVERY);
467-
xfs_defer_init(&dfops, &firstfsb);
468466

469467
/* Process deferred bmap item. */
470468
state = (bmap->me_flags & XFS_BMAP_EXTENT_UNWRITTEN) ?
@@ -479,42 +477,35 @@ xfs_bui_recover(
479477
break;
480478
default:
481479
error = -EFSCORRUPTED;
482-
goto err_dfops;
480+
goto err_inode;
483481
}
484482
xfs_trans_ijoin(tp, ip, 0);
485483

486484
count = bmap->me_len;
487-
error = xfs_trans_log_finish_bmap_update(tp, budp, &dfops, type,
485+
error = xfs_trans_log_finish_bmap_update(tp, budp, dfops, type,
488486
ip, whichfork, bmap->me_startoff,
489487
bmap->me_startblock, &count, state);
490488
if (error)
491-
goto err_dfops;
489+
goto err_inode;
492490

493491
if (count > 0) {
494492
ASSERT(type == XFS_BMAP_UNMAP);
495493
irec.br_startblock = bmap->me_startblock;
496494
irec.br_blockcount = count;
497495
irec.br_startoff = bmap->me_startoff;
498496
irec.br_state = state;
499-
error = xfs_bmap_unmap_extent(tp->t_mountp, &dfops, ip, &irec);
497+
error = xfs_bmap_unmap_extent(tp->t_mountp, dfops, ip, &irec);
500498
if (error)
501-
goto err_dfops;
499+
goto err_inode;
502500
}
503501

504-
/* Finish transaction, free inodes. */
505-
error = xfs_defer_finish(&tp, &dfops);
506-
if (error)
507-
goto err_dfops;
508-
509502
set_bit(XFS_BUI_RECOVERED, &buip->bui_flags);
510503
error = xfs_trans_commit(tp);
511504
xfs_iunlock(ip, XFS_ILOCK_EXCL);
512505
IRELE(ip);
513506

514507
return error;
515508

516-
err_dfops:
517-
xfs_defer_cancel(&dfops);
518509
err_inode:
519510
xfs_trans_cancel(tp);
520511
if (ip) {

fs/xfs/xfs_bmap_item.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ struct xfs_bud_log_item *xfs_bud_init(struct xfs_mount *,
9393
struct xfs_bui_log_item *);
9494
void xfs_bui_item_free(struct xfs_bui_log_item *);
9595
void xfs_bui_release(struct xfs_bui_log_item *);
96-
int xfs_bui_recover(struct xfs_mount *mp, struct xfs_bui_log_item *buip);
96+
int xfs_bui_recover(struct xfs_mount *mp, struct xfs_bui_log_item *buip,
97+
struct xfs_defer_ops *dfops);
9798

9899
#endif /* __XFS_BMAP_ITEM_H__ */

fs/xfs/xfs_buf.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1815,22 +1815,27 @@ xfs_alloc_buftarg(
18151815
btp->bt_daxdev = dax_dev;
18161816

18171817
if (xfs_setsize_buftarg_early(btp, bdev))
1818-
goto error;
1818+
goto error_free;
18191819

18201820
if (list_lru_init(&btp->bt_lru))
1821-
goto error;
1821+
goto error_free;
18221822

18231823
if (percpu_counter_init(&btp->bt_io_count, 0, GFP_KERNEL))
1824-
goto error;
1824+
goto error_lru;
18251825

18261826
btp->bt_shrinker.count_objects = xfs_buftarg_shrink_count;
18271827
btp->bt_shrinker.scan_objects = xfs_buftarg_shrink_scan;
18281828
btp->bt_shrinker.seeks = DEFAULT_SEEKS;
18291829
btp->bt_shrinker.flags = SHRINKER_NUMA_AWARE;
1830-
register_shrinker(&btp->bt_shrinker);
1830+
if (register_shrinker(&btp->bt_shrinker))
1831+
goto error_pcpu;
18311832
return btp;
18321833

1833-
error:
1834+
error_pcpu:
1835+
percpu_counter_destroy(&btp->bt_io_count);
1836+
error_lru:
1837+
list_lru_destroy(&btp->bt_lru);
1838+
error_free:
18341839
kmem_free(btp);
18351840
return NULL;
18361841
}

fs/xfs/xfs_dquot.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -970,14 +970,22 @@ xfs_qm_dqflush_done(
970970
* holding the lock before removing the dquot from the AIL.
971971
*/
972972
if ((lip->li_flags & XFS_LI_IN_AIL) &&
973-
lip->li_lsn == qip->qli_flush_lsn) {
973+
((lip->li_lsn == qip->qli_flush_lsn) ||
974+
(lip->li_flags & XFS_LI_FAILED))) {
974975

975976
/* xfs_trans_ail_delete() drops the AIL lock. */
976977
spin_lock(&ailp->xa_lock);
977-
if (lip->li_lsn == qip->qli_flush_lsn)
978+
if (lip->li_lsn == qip->qli_flush_lsn) {
978979
xfs_trans_ail_delete(ailp, lip, SHUTDOWN_CORRUPT_INCORE);
979-
else
980+
} else {
981+
/*
982+
* Clear the failed state since we are about to drop the
983+
* flush lock
984+
*/
985+
if (lip->li_flags & XFS_LI_FAILED)
986+
xfs_clear_li_failed(lip);
980987
spin_unlock(&ailp->xa_lock);
988+
}
981989
}
982990

983991
/*

fs/xfs/xfs_dquot_item.c

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,20 +137,55 @@ xfs_qm_dqunpin_wait(
137137
wait_event(dqp->q_pinwait, (atomic_read(&dqp->q_pincount) == 0));
138138
}
139139

140+
/*
141+
* Callback used to mark a buffer with XFS_LI_FAILED when items in the buffer
142+
* have been failed during writeback
143+
*
144+
* this informs the AIL that the dquot is already flush locked on the next push,
145+
* and acquires a hold on the buffer to ensure that it isn't reclaimed before
146+
* dirty data makes it to disk.
147+
*/
148+
STATIC void
149+
xfs_dquot_item_error(
150+
struct xfs_log_item *lip,
151+
struct xfs_buf *bp)
152+
{
153+
struct xfs_dquot *dqp;
154+
155+
dqp = DQUOT_ITEM(lip)->qli_dquot;
156+
ASSERT(!completion_done(&dqp->q_flush));
157+
xfs_set_li_failed(lip, bp);
158+
}
159+
140160
STATIC uint
141161
xfs_qm_dquot_logitem_push(
142162
struct xfs_log_item *lip,
143163
struct list_head *buffer_list) __releases(&lip->li_ailp->xa_lock)
144164
__acquires(&lip->li_ailp->xa_lock)
145165
{
146166
struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot;
147-
struct xfs_buf *bp = NULL;
167+
struct xfs_buf *bp = lip->li_buf;
148168
uint rval = XFS_ITEM_SUCCESS;
149169
int error;
150170

151171
if (atomic_read(&dqp->q_pincount) > 0)
152172
return XFS_ITEM_PINNED;
153173

174+
/*
175+
* The buffer containing this item failed to be written back
176+
* previously. Resubmit the buffer for IO
177+
*/
178+
if (lip->li_flags & XFS_LI_FAILED) {
179+
if (!xfs_buf_trylock(bp))
180+
return XFS_ITEM_LOCKED;
181+
182+
if (!xfs_buf_resubmit_failed_buffers(bp, lip, buffer_list))
183+
rval = XFS_ITEM_FLUSHING;
184+
185+
xfs_buf_unlock(bp);
186+
return rval;
187+
}
188+
154189
if (!xfs_dqlock_nowait(dqp))
155190
return XFS_ITEM_LOCKED;
156191

@@ -242,7 +277,8 @@ static const struct xfs_item_ops xfs_dquot_item_ops = {
242277
.iop_unlock = xfs_qm_dquot_logitem_unlock,
243278
.iop_committed = xfs_qm_dquot_logitem_committed,
244279
.iop_push = xfs_qm_dquot_logitem_push,
245-
.iop_committing = xfs_qm_dquot_logitem_committing
280+
.iop_committing = xfs_qm_dquot_logitem_committing,
281+
.iop_error = xfs_dquot_item_error
246282
};
247283

248284
/*

fs/xfs/xfs_inode.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2400,6 +2400,24 @@ xfs_ifree_cluster(
24002400
return 0;
24012401
}
24022402

2403+
/*
2404+
* Free any local-format buffers sitting around before we reset to
2405+
* extents format.
2406+
*/
2407+
static inline void
2408+
xfs_ifree_local_data(
2409+
struct xfs_inode *ip,
2410+
int whichfork)
2411+
{
2412+
struct xfs_ifork *ifp;
2413+
2414+
if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL)
2415+
return;
2416+
2417+
ifp = XFS_IFORK_PTR(ip, whichfork);
2418+
xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
2419+
}
2420+
24032421
/*
24042422
* This is called to return an inode to the inode free list.
24052423
* The inode should already be truncated to 0 length and have
@@ -2437,6 +2455,9 @@ xfs_ifree(
24372455
if (error)
24382456
return error;
24392457

2458+
xfs_ifree_local_data(ip, XFS_DATA_FORK);
2459+
xfs_ifree_local_data(ip, XFS_ATTR_FORK);
2460+
24402461
VFS_I(ip)->i_mode = 0; /* mark incore inode as free */
24412462
ip->i_d.di_flags = 0;
24422463
ip->i_d.di_dmevmask = 0;

0 commit comments

Comments
 (0)