[XFS] Add support for hotplug CPUs to the per-CPU superblock counters by
David Chinner [Tue, 14 Mar 2006 02:23:52 +0000 (13:23 +1100)]
registering a notifier callback that listens to CPU up/down events to
modify the counters appropriately.

SGI-PV: 949726
SGI-Modid: xfs-linux-melb:xfs-kern:25214a

Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Nathan Scott <nathans@sgi.com>

fs/xfs/linux-2.6/xfs_linux.h
fs/xfs/xfs_mount.c
fs/xfs/xfs_mount.h

index e2be649..9fdc14c 100644 (file)
@@ -73,6 +73,8 @@
 #include <linux/list.h>
 #include <linux/proc_fs.h>
 #include <linux/sort.h>
+#include <linux/cpu.h>
+#include <linux/notifier.h>
 
 #include <asm/page.h>
 #include <asm/div64.h>
index 9b43b7b..a64110b 100644 (file)
@@ -60,6 +60,7 @@ STATIC int    xfs_icsb_modify_counters(xfs_mount_t *, xfs_sb_field_t,
                                                int, int);
 STATIC int     xfs_icsb_modify_counters_locked(xfs_mount_t *, xfs_sb_field_t,
                                                int, int);
+STATIC int     xfs_icsb_disable_counter(xfs_mount_t *, xfs_sb_field_t);
 
 #else
 
@@ -1716,9 +1717,72 @@ xfs_mount_log_sbunit(
  * To ensure counters don't remain disabled, they are rebalanced when
  * the global resource goes above a higher threshold (i.e. some hysteresis
  * is present to prevent thrashing).
+ */
+
+/*
+ * hot-plug CPU notifier support.
  *
- * Note: hotplug CPUs not yet supported
+ * We cannot use the hotcpu_register() function because it does
+ * not allow notifier instances. We need a notifier per filesystem
+ * as we need to be able to identify the filesystem to balance
+ * the counters out. This is acheived by having a notifier block
+ * embedded in the xfs_mount_t and doing pointer magic to get the
+ * mount pointer from the notifier block address.
  */
+STATIC int
+xfs_icsb_cpu_notify(
+       struct notifier_block *nfb,
+       unsigned long action,
+       void *hcpu)
+{
+       xfs_icsb_cnts_t *cntp;
+       xfs_mount_t     *mp;
+       int             s;
+
+       mp = (xfs_mount_t *)container_of(nfb, xfs_mount_t, m_icsb_notifier);
+       cntp = (xfs_icsb_cnts_t *)
+                       per_cpu_ptr(mp->m_sb_cnts, (unsigned long)hcpu);
+       switch (action) {
+       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;
+               break;
+       case CPU_ONLINE:
+               xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0);
+               xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0);
+               xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0);
+               break;
+       case CPU_DEAD:
+               /* Disable all the counters, then fold the dead cpu's
+                * count into the total on the global superblock and
+                * re-enable the counters. */
+               s = XFS_SB_LOCK(mp);
+               xfs_icsb_disable_counter(mp, XFS_SBS_ICOUNT);
+               xfs_icsb_disable_counter(mp, XFS_SBS_IFREE);
+               xfs_icsb_disable_counter(mp, XFS_SBS_FDBLOCKS);
+
+               mp->m_sb.sb_icount += cntp->icsb_icount;
+               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;
+
+               xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, XFS_ICSB_SB_LOCKED);
+               xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, XFS_ICSB_SB_LOCKED);
+               xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, XFS_ICSB_SB_LOCKED);
+               XFS_SB_UNLOCK(mp, s);
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
 int
 xfs_icsb_init_counters(
        xfs_mount_t     *mp)
@@ -1730,6 +1794,10 @@ xfs_icsb_init_counters(
        if (mp->m_sb_cnts == NULL)
                return -ENOMEM;
 
+       mp->m_icsb_notifier.notifier_call = xfs_icsb_cpu_notify;
+       mp->m_icsb_notifier.priority = 0;
+       register_cpu_notifier(&mp->m_icsb_notifier);
+
        for_each_online_cpu(i) {
                cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);
                spin_lock_init(&cntp->icsb_lock);
@@ -1746,8 +1814,10 @@ STATIC void
 xfs_icsb_destroy_counters(
        xfs_mount_t     *mp)
 {
-       if (mp->m_sb_cnts)
+       if (mp->m_sb_cnts) {
+               unregister_cpu_notifier(&mp->m_icsb_notifier);
                free_percpu(mp->m_sb_cnts);
+       }
 }
 
 
index 7cca511..9d2ffbd 100644 (file)
@@ -401,6 +401,7 @@ typedef struct xfs_mount {
 #ifdef HAVE_PERCPU_SB
        xfs_icsb_cnts_t         *m_sb_cnts;     /* per-cpu superblock counters */
        unsigned long           m_icsb_counters; /* disabled per-cpu counters */
+       struct notifier_block   m_icsb_notifier; /* hotplug cpu notifier */
 #endif
 } xfs_mount_t;