Pull xfs fix from Carlos Maiolino: "A single fix for a race in xfs buffer cache which may lead to filesystem shutdown due to inconsistent metadata if the buffer lookup happens to find an old dead buffer still in the cache" * tag 'xfs-fixes-7.1-rc5' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: xfs: fix a buffer lookup against removal race
Unified · Split
| @@ -472,6 +472,7 @@ xfs_buf_find_insert( · 471 unmodified lines | |||
| 472 | /* The new buffer keeps the perag reference until it is freed. */ | 472 | /* The new buffer keeps the perag reference until it is freed. */ |
| 473 | new_bp->b_pag = pag; | 473 | new_bp->b_pag = pag; |
| 474 | 474 | ||
| 475 | retry: | ||
| 475 | rcu_read_lock(); | 476 | rcu_read_lock(); |
| 476 | bp = rhashtable_lookup_get_insert_fast(&btp->bt_hash, | 477 | bp = rhashtable_lookup_get_insert_fast(&btp->bt_hash, |
| 477 | &new_bp->b_rhash_head, xfs_buf_hash_params); | 478 | &new_bp->b_rhash_head, xfs_buf_hash_params); |
| @@ -480,8 +481,16 @@ xfs_buf_find_insert( · 2 unmodified lines | |||
| 480 | error = PTR_ERR(bp); | 481 | error = PTR_ERR(bp); |
| 481 | goto out_free_buf; | 482 | goto out_free_buf; |
| 482 | } | 483 | } |
| 483 | if (bp && lockref_get_not_dead(&bp->b_lockref)) { | 484 | if (bp) { |
| 484 | /* found an existing buffer */ | 485 | /* |
| 486 | * If there is an existing buffer with a dead lockref, retry | ||
| 487 | * until the new buffer is added, or a usable buffer is found. | ||
| 488 | */ | ||
| 489 | if (!lockref_get_not_dead(&bp->b_lockref)) { | ||
| 490 | rcu_read_unlock(); | ||
| 491 | cpu_relax(); | ||
| 492 | goto retry; | ||
| 493 | } | ||
| 485 | rcu_read_unlock(); | 494 | rcu_read_unlock(); |
| 486 | error = xfs_buf_find_lock(bp, flags); | 495 | error = xfs_buf_find_lock(bp, flags); |
| 487 | if (error) | 496 | if (error) |
| @@ -820,15 +829,20 @@ xfs_buf_destroy( · 332 unmodified lines | |||
| 820 | ASSERT(__lockref_is_dead(&bp->b_lockref)); | 829 | ASSERT(__lockref_is_dead(&bp->b_lockref)); |
| 821 | ASSERT(!(bp->b_flags & _XBF_DELWRI_Q)); | 830 | ASSERT(!(bp->b_flags & _XBF_DELWRI_Q)); |
| 822 | 831 | ||
| 832 | if (bp->b_pag) | ||
| 833 | xfs_perag_put(bp->b_pag); | ||
| 834 | xfs_buf_free(bp); | ||
| 835 | } | ||
| 836 | |||
| 837 | static inline void | ||
| 838 | xfs_buf_kill( | ||
| 839 | struct xfs_buf *bp) | ||
| 840 | { | ||
| 841 | lockref_mark_dead(&bp->b_lockref); | ||
| 823 | if (!xfs_buf_is_uncached(bp)) { | 842 | if (!xfs_buf_is_uncached(bp)) { |
| 824 | rhashtable_remove_fast(&bp->b_target->bt_hash, | 843 | rhashtable_remove_fast(&bp->b_target->bt_hash, |
| 825 | &bp->b_rhash_head, xfs_buf_hash_params); | 844 | &bp->b_rhash_head, xfs_buf_hash_params); |
| 826 | |||
| 827 | if (bp->b_pag) | ||
| 828 | xfs_perag_put(bp->b_pag); | ||
| 829 | } | 845 | } |
| 830 | |||
| 831 | xfs_buf_free(bp); | ||
| 832 | } | 846 | } |
| 833 | 847 | ||
| 834 | /* | 848 | /* |
| @@ -851,7 +865,7 @@ xfs_buf_rele( · 16 unmodified lines | |||
| 851 | return; | 865 | return; |
| 852 | 866 | ||
| 853 | kill: | 867 | kill: |
| 854 | lockref_mark_dead(&bp->b_lockref); | 868 | xfs_buf_kill(bp); |
| 855 | list_lru_del_obj(&bp->b_target->bt_lru, &bp->b_lru); | 869 | list_lru_del_obj(&bp->b_target->bt_lru, &bp->b_lru); |
| 856 | spin_unlock(&bp->b_lockref.lock); | 870 | spin_unlock(&bp->b_lockref.lock); |
| 857 | 871 | ||
| @@ -1433,7 +1447,7 @@ xfs_buftarg_drain_rele( · 575 unmodified lines | |||
| 1433 | return LRU_SKIP; | 1447 | return LRU_SKIP; |
| 1434 | } | 1448 | } |
| 1435 | 1449 | ||
| 1436 | lockref_mark_dead(&bp->b_lockref); | 1450 | xfs_buf_kill(bp); |
| 1437 | list_lru_isolate_move(lru, item, dispose); | 1451 | list_lru_isolate_move(lru, item, dispose); |
| 1438 | spin_unlock(&bp->b_lockref.lock); | 1452 | spin_unlock(&bp->b_lockref.lock); |
| 1439 | return LRU_REMOVED; | 1453 | return LRU_REMOVED; |
| @@ -1545,7 +1559,7 @@ xfs_buftarg_isolate( · 105 unmodified lines | |||
| 1545 | return LRU_ROTATE; | 1559 | return LRU_ROTATE; |
| 1546 | } | 1560 | } |
| 1547 | 1561 | ||
| 1548 | lockref_mark_dead(&bp->b_lockref); | 1562 | xfs_buf_kill(bp); |
| 1549 | list_lru_isolate_move(lru, item, dispose); | 1563 | list_lru_isolate_move(lru, item, dispose); |
| 1550 | spin_unlock(&bp->b_lockref.lock); | 1564 | spin_unlock(&bp->b_lockref.lock); |
| 1551 | return LRU_REMOVED; | 1565 | return LRU_REMOVED; |