#include "xfs_platform.h"
#include "xfs_fs.h"
#include "xfs_shared.h"
#include "xfs_format.h"
#include "xfs_trans_resv.h"
#include "xfs_mount.h"
#include "xfs_ag.h"
#include "xfs_trace.h"
static DEFINE_STATIC_KEY_FALSE(xfs_defer_drain_waiter_gate);
void
xfs_defer_drain_wait_disable(void)
{
static_branch_dec(&xfs_defer_drain_waiter_gate);
}
void
xfs_defer_drain_wait_enable(void)
{
static_branch_inc(&xfs_defer_drain_waiter_gate);
}
void
xfs_defer_drain_init(
struct xfs_defer_drain *dr)
{
atomic_set(&dr->dr_count, 0);
init_waitqueue_head(&dr->dr_waiters);
}
void
xfs_defer_drain_free(struct xfs_defer_drain *dr)
{
ASSERT(atomic_read(&dr->dr_count) == 0);
}
static inline void xfs_defer_drain_grab(struct xfs_defer_drain *dr)
{
atomic_inc(&dr->dr_count);
}
static inline bool has_waiters(struct wait_queue_head *wq_head)
{
smp_mb__after_atomic();
return waitqueue_active(wq_head);
}
static inline void xfs_defer_drain_rele(struct xfs_defer_drain *dr)
{
if (atomic_dec_and_test(&dr->dr_count) &&
static_branch_unlikely(&xfs_defer_drain_waiter_gate) &&
has_waiters(&dr->dr_waiters))
wake_up(&dr->dr_waiters);
}
static inline bool xfs_defer_drain_busy(struct xfs_defer_drain *dr)
{
return atomic_read(&dr->dr_count) > 0;
}
static inline int xfs_defer_drain_wait(struct xfs_defer_drain *dr)
{
return wait_event_killable(dr->dr_waiters, !xfs_defer_drain_busy(dr));
}
struct xfs_group *
xfs_group_intent_get(
struct xfs_mount *mp,
xfs_fsblock_t fsbno,
enum xfs_group_type type)
{
struct xfs_group *xg;
xg = xfs_group_get_by_fsb(mp, fsbno, type);
if (!xg)
return NULL;
trace_xfs_group_intent_hold(xg, __return_address);
xfs_defer_drain_grab(&xg->xg_intents_drain);
return xg;
}
void
xfs_group_intent_put(
struct xfs_group *xg)
{
trace_xfs_group_intent_rele(xg, __return_address);
xfs_defer_drain_rele(&xg->xg_intents_drain);
xfs_group_put(xg);
}
int
xfs_group_intent_drain(
struct xfs_group *xg)
{
trace_xfs_group_wait_intents(xg, __return_address);
return xfs_defer_drain_wait(&xg->xg_intents_drain);
}
bool
xfs_group_intent_busy(
struct xfs_group *xg)
{
return xfs_defer_drain_busy(&xg->xg_intents_drain);
}