LCOV - code coverage report
Current view: top level - fs/xfs - xfs_drain.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-djwx @ Mon Jul 31 20:08:22 PDT 2023 Lines: 47 47 100.0 %
Date: 2023-07-31 20:08:22 Functions: 12 12 100.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  * Copyright (C) 2022-2023 Oracle.  All Rights Reserved.
       4             :  * Author: Darrick J. Wong <djwong@kernel.org>
       5             :  */
       6             : #include "xfs.h"
       7             : #include "xfs_fs.h"
       8             : #include "xfs_shared.h"
       9             : #include "xfs_format.h"
      10             : #include "xfs_trans_resv.h"
      11             : #include "xfs_mount.h"
      12             : #include "xfs_ag.h"
      13             : #include "xfs_trace.h"
      14             : 
      15             : /*
      16             :  * Use a static key here to reduce the overhead of xfs_drain_rele.  If the
      17             :  * compiler supports jump labels, the static branch will be replaced by a nop
      18             :  * sled when there are no xfs_drain_wait callers.  Online fsck is currently
      19             :  * the only caller, so this is a reasonable tradeoff.
      20             :  *
      21             :  * Note: Patching the kernel code requires taking the cpu hotplug lock.  Other
      22             :  * parts of the kernel allocate memory with that lock held, which means that
      23             :  * XFS callers cannot hold any locks that might be used by memory reclaim or
      24             :  * writeback when calling the static_branch_{inc,dec} functions.
      25             :  */
      26             : static DEFINE_STATIC_KEY_FALSE(xfs_drain_waiter_gate);
      27             : 
      28             : void
      29      103676 : xfs_drain_wait_disable(void)
      30             : {
      31      103676 :         static_branch_dec(&xfs_drain_waiter_gate);
      32      103677 : }
      33             : 
      34             : void
      35      103673 : xfs_drain_wait_enable(void)
      36             : {
      37      103673 :         static_branch_inc(&xfs_drain_waiter_gate);
      38      103677 : }
      39             : 
      40             : void
      41      444281 : xfs_defer_drain_init(
      42             :         struct xfs_defer_drain  *dr)
      43             : {
      44      444281 :         atomic_set(&dr->dr_count, 0);
      45      444281 :         init_waitqueue_head(&dr->dr_waiters);
      46      444281 : }
      47             : 
      48             : void
      49      444321 : xfs_defer_drain_free(struct xfs_defer_drain     *dr)
      50             : {
      51      444321 :         ASSERT(atomic_read(&dr->dr_count) == 0);
      52      444321 : }
      53             : 
      54             : /* Increase the pending intent count. */
      55             : static inline void xfs_defer_drain_grab(struct xfs_defer_drain *dr)
      56             : {
      57   768643249 :         atomic_inc(&dr->dr_count);
      58             : }
      59             : 
      60             : static inline bool has_waiters(struct wait_queue_head *wq_head)
      61             : {
      62             :         /*
      63             :          * This memory barrier is paired with the one in set_current_state on
      64             :          * the waiting side.
      65             :          */
      66      539941 :         smp_mb__after_atomic();
      67      539941 :         return waitqueue_active(wq_head);
      68             : }
      69             : 
      70             : /* Decrease the pending intent count, and wake any waiters, if appropriate. */
      71   768668997 : static inline void xfs_defer_drain_rele(struct xfs_defer_drain *dr)
      72             : {
      73   768668997 :         if (atomic_dec_and_test(&dr->dr_count) &&
      74   279894753 :             static_branch_unlikely(&xfs_drain_waiter_gate) &&
      75             :             has_waiters(&dr->dr_waiters))
      76       55140 :                 wake_up(&dr->dr_waiters);
      77   768704428 : }
      78             : 
      79             : /* Are there intents pending? */
      80             : static inline bool xfs_defer_drain_busy(struct xfs_defer_drain *dr)
      81             : {
      82    10095872 :         return atomic_read(&dr->dr_count) > 0;
      83             : }
      84             : 
      85             : /*
      86             :  * Wait for the pending intent count for a drain to hit zero.
      87             :  *
      88             :  * Callers must not hold any locks that would prevent intents from being
      89             :  * finished.
      90             :  */
      91       48152 : static inline int xfs_defer_drain_wait(struct xfs_defer_drain *dr)
      92             : {
      93      103288 :         return wait_event_killable(dr->dr_waiters, !xfs_defer_drain_busy(dr));
      94             : }
      95             : 
      96             : /*
      97             :  * Get a passive reference to an AG and declare an intent to update its
      98             :  * metadata.
      99             :  */
     100             : struct xfs_perag *
     101   768587067 : xfs_perag_intent_get(
     102             :         struct xfs_mount        *mp,
     103             :         xfs_agnumber_t          agno)
     104             : {
     105   768587067 :         struct xfs_perag        *pag;
     106             : 
     107   768587067 :         pag = xfs_perag_get(mp, agno);
     108   768684277 :         if (!pag)
     109             :                 return NULL;
     110             : 
     111   768684277 :         xfs_perag_intent_hold(pag);
     112   768684277 :         return pag;
     113             : }
     114             : 
     115             : /*
     116             :  * Release our intent to update this AG's metadata, and then release our
     117             :  * passive ref to the AG.
     118             :  */
     119             : void
     120   768704104 : xfs_perag_intent_put(
     121             :         struct xfs_perag        *pag)
     122             : {
     123   768704104 :         xfs_perag_intent_rele(pag);
     124   768696652 :         xfs_perag_put(pag);
     125   768702689 : }
     126             : 
     127             : /*
     128             :  * Declare an intent to update AG metadata.  Other threads that need exclusive
     129             :  * access can decide to back off if they see declared intentions.
     130             :  */
     131             : void
     132   768677669 : xfs_perag_intent_hold(
     133             :         struct xfs_perag        *pag)
     134             : {
     135   768677669 :         trace_xfs_perag_intent_hold(pag, __return_address);
     136   768643249 :         xfs_defer_drain_grab(&pag->pag_intents_drain);
     137   768694119 : }
     138             : 
     139             : /* Release our intent to update this AG's metadata. */
     140             : void
     141   768690885 : xfs_perag_intent_rele(
     142             :         struct xfs_perag        *pag)
     143             : {
     144   768690885 :         trace_xfs_perag_intent_rele(pag, __return_address);
     145   768669643 :         xfs_defer_drain_rele(&pag->pag_intents_drain);
     146   768698025 : }
     147             : 
     148             : /*
     149             :  * Wait for the intent update count for this AG to hit zero.
     150             :  * Callers must not hold any AG header buffers.
     151             :  */
     152             : int
     153       48152 : xfs_perag_intent_drain(
     154             :         struct xfs_perag        *pag)
     155             : {
     156       48152 :         trace_xfs_perag_wait_intents(pag, __return_address);
     157       48152 :         return xfs_defer_drain_wait(&pag->pag_intents_drain);
     158             : }
     159             : 
     160             : /* Has anyone declared an intent to update this AG? */
     161             : bool
     162     9945476 : xfs_perag_intent_busy(
     163             :         struct xfs_perag        *pag)
     164             : {
     165     9945476 :         return xfs_defer_drain_busy(&pag->pag_intents_drain);
     166             : }

Generated by: LCOV version 1.14