From 01e1b69cfcdcfdd5b405165eaba29428f8b18a7c Mon Sep 17 00:00:00 2001 From: David Chinner Date: Tue, 14 Mar 2006 13:29:16 +1100 Subject: [XFS] using a spinlock per cpu for superblock counter exclusion results in a preēmpt counter overflow at 256p and above. Change the exclusion mechanism to use atomic bit operations and busy wait loops to emulate the spin lock exclusion mechanism but without the preempt count issues. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SGI-PV: 950027 SGI-Modid: xfs-linux-melb:xfs-kern:25338a Signed-off-by: David Chinner Signed-off-by: Nathan Scott --- fs/xfs/linux-2.6/xfs_linux.h | 1 + fs/xfs/xfs_mount.c | 37 ++++++++++++++++++++++++------------- fs/xfs/xfs_mount.h | 4 +++- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h index 9fdc14cffb70..bd88ccb0cad0 100644 --- a/fs/xfs/linux-2.6/xfs_linux.h +++ b/fs/xfs/linux-2.6/xfs_linux.h @@ -75,6 +75,7 @@ #include #include #include +#include #include #include diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index a64110b9023b..d62aee027368 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -1746,10 +1746,7 @@ xfs_icsb_cpu_notify( case CPU_UP_PREPARE: /* Easy Case - initialize the area and locks, and * then rebalance when online does everything else for us. */ - spin_lock_init(&cntp->icsb_lock); - cntp->icsb_icount = 0; - cntp->icsb_ifree = 0; - cntp->icsb_fdblocks = 0; + memset(cntp, 0, sizeof(xfs_icsb_cnts_t)); break; case CPU_ONLINE: xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0); @@ -1769,9 +1766,7 @@ xfs_icsb_cpu_notify( mp->m_sb.sb_ifree += cntp->icsb_ifree; mp->m_sb.sb_fdblocks += cntp->icsb_fdblocks; - cntp->icsb_icount = 0; - cntp->icsb_ifree = 0; - cntp->icsb_fdblocks = 0; + memset(cntp, 0, sizeof(xfs_icsb_cnts_t)); xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, XFS_ICSB_SB_LOCKED); xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, XFS_ICSB_SB_LOCKED); @@ -1800,7 +1795,7 @@ xfs_icsb_init_counters( for_each_online_cpu(i) { cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i); - spin_lock_init(&cntp->icsb_lock); + memset(cntp, 0, sizeof(xfs_icsb_cnts_t)); } /* * start with all counters disabled so that the @@ -1820,6 +1815,22 @@ xfs_icsb_destroy_counters( } } +STATIC inline void +xfs_icsb_lock_cntr( + xfs_icsb_cnts_t *icsbp) +{ + while (test_and_set_bit(XFS_ICSB_FLAG_LOCK, &icsbp->icsb_flags)) { + ndelay(1000); + } +} + +STATIC inline void +xfs_icsb_unlock_cntr( + xfs_icsb_cnts_t *icsbp) +{ + clear_bit(XFS_ICSB_FLAG_LOCK, &icsbp->icsb_flags); +} + STATIC inline void xfs_icsb_lock_all_counters( @@ -1830,7 +1841,7 @@ xfs_icsb_lock_all_counters( for_each_online_cpu(i) { cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i); - spin_lock(&cntp->icsb_lock); + xfs_icsb_lock_cntr(cntp); } } @@ -1843,7 +1854,7 @@ xfs_icsb_unlock_all_counters( for_each_online_cpu(i) { cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i); - spin_unlock(&cntp->icsb_lock); + xfs_icsb_unlock_cntr(cntp); } } @@ -2070,7 +2081,7 @@ xfs_icsb_modify_counters_int( again: cpu = get_cpu(); icsbp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, cpu), - spin_lock(&icsbp->icsb_lock); + xfs_icsb_lock_cntr(icsbp); if (unlikely(xfs_icsb_counter_disabled(mp, field))) goto slow_path; @@ -2104,7 +2115,7 @@ again: BUG(); break; } - spin_unlock(&icsbp->icsb_lock); + xfs_icsb_unlock_cntr(icsbp); put_cpu(); if (locked) XFS_SB_UNLOCK(mp, s); @@ -2120,7 +2131,7 @@ again: * manner. */ slow_path: - spin_unlock(&icsbp->icsb_lock); + xfs_icsb_unlock_cntr(icsbp); put_cpu(); /* need to hold superblock incase we need diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 9d2ffbdc37a9..29cfcf0c11be 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -280,9 +280,11 @@ typedef struct xfs_icsb_cnts { uint64_t icsb_fdblocks; uint64_t icsb_ifree; uint64_t icsb_icount; - spinlock_t icsb_lock; + unsigned long icsb_flags; } xfs_icsb_cnts_t; +#define XFS_ICSB_FLAG_LOCK (1 << 0) /* counter lock bit */ + #define XFS_ICSB_SB_LOCKED (1 << 0) /* sb already locked */ #define XFS_ICSB_LAZY_COUNT (1 << 1) /* accuracy not needed */ -- cgit v1.2.3