summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/libxfs/xfs_ag.c4
-rw-r--r--fs/xfs/xfs_mount.c10
-rw-r--r--fs/xfs/xfs_mount.h19
-rw-r--r--fs/xfs/xfs_trace.h2
4 files changed, 24 insertions, 11 deletions
diff --git a/fs/xfs/libxfs/xfs_ag.c b/fs/xfs/libxfs/xfs_ag.c
index 27ba30f8f64b..2da2a366395c 100644
--- a/fs/xfs/libxfs/xfs_ag.c
+++ b/fs/xfs/libxfs/xfs_ag.c
@@ -314,7 +314,9 @@ xfs_initialize_perag(
spin_lock_init(&pag->pag_state_lock);
INIT_DELAYED_WORK(&pag->pag_blockgc_work, xfs_blockgc_worker);
INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
- xfs_drain_init(&pag->pag_intents);
+ error = xfs_drain_init(&pag->pag_intents);
+ if (error)
+ goto out_remove_pag;
init_waitqueue_head(&pag->pagb_wait);
pag->pagb_count = 0;
pag->pagb_tree = RB_ROOT;
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 6c84c6547a0b..2effc1647ce1 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -1390,15 +1390,14 @@ xfs_mod_delalloc(
/* Increase the pending intent count. */
static inline void xfs_drain_bump(struct xfs_drain *dr)
{
- atomic_inc(&dr->dr_count);
+ percpu_counter_add_batch(&dr->dr_count, 1, XFS_DRAIN_BATCH);
}
/* Decrease the pending intent count, and wake any waiters, if appropriate. */
static inline void xfs_drain_drop(struct xfs_drain *dr)
{
- if (atomic_dec_and_test(&dr->dr_count) &&
- wq_has_sleeper(&dr->dr_waiters))
- wake_up(&dr->dr_waiters);
+ percpu_counter_add_batch(&dr->dr_count, -1, XFS_DRAIN_BATCH);
+ wake_up(&dr->dr_waiters);
}
/*
@@ -1409,6 +1408,9 @@ static inline void xfs_drain_drop(struct xfs_drain *dr)
*/
static inline int xfs_drain_wait(struct xfs_drain *dr)
{
+ if (!xfs_drain_busy(dr))
+ return 0;
+
return wait_event_killable(dr->dr_waiters, !xfs_drain_busy(dr));
}
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index ddf438701022..3e4921304442 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -64,7 +64,7 @@ struct xfs_error_cfg {
*/
struct xfs_drain {
/* Number of items pending in some part of the filesystem. */
- atomic_t dr_count;
+ struct percpu_counter dr_count;
/* Queue to wait for dri_count to go to zero */
struct wait_queue_head dr_waiters;
@@ -76,21 +76,30 @@ bool xfs_ag_intents_busy(struct xfs_perag *pag);
void xfs_fs_bump_intents(struct xfs_mount *mp, xfs_fsblock_t fsb);
void xfs_fs_drop_intents(struct xfs_mount *mp, xfs_fsblock_t fsb);
+/*
+ * Use a large batch value for the drain counter so that writer threads
+ * can queue a large number of log intents before having to update the main
+ * counter.
+ */
+#define XFS_DRAIN_BATCH (1024)
+
/* Are there work items pending? */
static inline bool xfs_drain_busy(struct xfs_drain *dr)
{
- return atomic_read(&dr->dr_count) > 0;
+ return __percpu_counter_compare(&dr->dr_count, 0, XFS_DRAIN_BATCH) > 0;
}
-static inline void xfs_drain_init(struct xfs_drain *dr)
+static inline int xfs_drain_init(struct xfs_drain *dr)
{
- atomic_set(&dr->dr_count, 0);
init_waitqueue_head(&dr->dr_waiters);
+ return percpu_counter_init(&dr->dr_count, 0, GFP_KERNEL);
}
static inline void xfs_drain_free(struct xfs_drain *dr)
{
ASSERT(!xfs_drain_busy(dr));
+
+ percpu_counter_destroy(&dr->dr_count);
}
#else
struct xfs_drain { /* empty */ };
@@ -104,7 +113,7 @@ static inline void
xfs_fs_drop_intents(struct xfs_mount *mp, xfs_fsblock_t fsb)
{
}
-# define xfs_drain_init(dr) ((void)0)
+# define xfs_drain_init(dr) (0)
# define xfs_drain_free(dr) ((void)0)
#endif /* CONFIG_XFS_DRAIN_INTENTS */
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index fae3b0fe0971..c584ff52bb40 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -4259,7 +4259,7 @@ DECLARE_EVENT_CLASS(xfs_perag_intents_class,
TP_fast_assign(
__entry->dev = pag->pag_mount->m_super->s_dev;
__entry->agno = pag->pag_agno;
- __entry->nr_intents = atomic_read(&pag->pag_intents.dr_count);
+ __entry->nr_intents = percpu_counter_sum(&pag->pag_intents.dr_count);
__entry->caller_ip = caller_ip;
),
TP_printk("dev %d:%d agno 0x%x intents %ld caller %pS",