Diff for /xfs-linux/xfs_mount.c between versions 1.387 and 1.388

version 1.387, 2006/11/30 14:40:05 version 1.388, 2006/12/04 02:51:48
Line 52  STATIC void xfs_unmountfs_wait(xfs_mount Line 52  STATIC void xfs_unmountfs_wait(xfs_mount
   
 #ifdef HAVE_PERCPU_SB  #ifdef HAVE_PERCPU_SB
 STATIC void     xfs_icsb_destroy_counters(xfs_mount_t *);  STATIC void     xfs_icsb_destroy_counters(xfs_mount_t *);
 STATIC void     xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t, int);  STATIC void     xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t, int,
   int);
 STATIC void     xfs_icsb_sync_counters(xfs_mount_t *);  STATIC void     xfs_icsb_sync_counters(xfs_mount_t *);
 STATIC int      xfs_icsb_modify_counters(xfs_mount_t *, xfs_sb_field_t,  STATIC int      xfs_icsb_modify_counters(xfs_mount_t *, xfs_sb_field_t,
                                                 int, int);                                                  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);  STATIC int      xfs_icsb_disable_counter(xfs_mount_t *, xfs_sb_field_t);
   
 #else  #else
   
 #define xfs_icsb_destroy_counters(mp)                   do { } while (0)  #define xfs_icsb_destroy_counters(mp)                   do { } while (0)
 #define xfs_icsb_balance_counter(mp, a, b)              do { } while (0)  #define xfs_icsb_balance_counter(mp, a, b, c)           do { } while (0)
 #define xfs_icsb_sync_counters(mp)                      do { } while (0)  #define xfs_icsb_sync_counters(mp)                      do { } while (0)
 #define xfs_icsb_modify_counters(mp, a, b, c)           do { } while (0)  #define xfs_icsb_modify_counters(mp, a, b, c)           do { } while (0)
 #define xfs_icsb_modify_counters_locked(mp, a, b, c)    do { } while (0)  
   
 #endif  #endif
   
Line 545  xfs_readsb(xfs_mount_t *mp, int flags) Line 543  xfs_readsb(xfs_mount_t *mp, int flags)
                 ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);                  ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
         }          }
   
         xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0);          mutex_lock(&mp->m_icsb_mutex);
         xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0);          xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0, 0);
         xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0);          xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0, 0);
           xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0, 0);
           mutex_unlock(&mp->m_icsb_mutex);
   
         mp->m_sb_bp = bp;          mp->m_sb_bp = bp;
         xfs_buf_relse(bp);          xfs_buf_relse(bp);
Line 1485  xfs_mod_incore_sb_batch(xfs_mount_t *mp, Line 1485  xfs_mod_incore_sb_batch(xfs_mount_t *mp,
                 case XFS_SBS_IFREE:                  case XFS_SBS_IFREE:
                 case XFS_SBS_FDBLOCKS:                  case XFS_SBS_FDBLOCKS:
                         if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) {                          if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) {
                                 status = xfs_icsb_modify_counters_locked(mp,                                  XFS_SB_UNLOCK(mp, s);
                                   status = xfs_icsb_modify_counters(mp,
                                                         msbp->msb_field,                                                          msbp->msb_field,
                                                         msbp->msb_delta, rsvd);                                                          msbp->msb_delta, rsvd);
                                   s = XFS_SB_LOCK(mp);
                                 break;                                  break;
                         }                          }
                         /* FALLTHROUGH */                          /* FALLTHROUGH */
Line 1521  xfs_mod_incore_sb_batch(xfs_mount_t *mp, Line 1523  xfs_mod_incore_sb_batch(xfs_mount_t *mp,
                         case XFS_SBS_IFREE:                          case XFS_SBS_IFREE:
                         case XFS_SBS_FDBLOCKS:                          case XFS_SBS_FDBLOCKS:
                                 if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) {                                  if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) {
                                         status =                                          XFS_SB_UNLOCK(mp, s);
                                             xfs_icsb_modify_counters_locked(mp,                                          status = xfs_icsb_modify_counters(mp,
                                                         msbp->msb_field,                                                          msbp->msb_field,
                                                         -(msbp->msb_delta),                                                          -(msbp->msb_delta),
                                                         rsvd);                                                          rsvd);
                                           s = XFS_SB_LOCK(mp);
                                         break;                                          break;
                                 }                                  }
                                 /* FALLTHROUGH */                                  /* FALLTHROUGH */
Line 1733  xfs_icsb_cpu_notify( Line 1736  xfs_icsb_cpu_notify(
                 memset(cntp, 0, sizeof(xfs_icsb_cnts_t));                  memset(cntp, 0, sizeof(xfs_icsb_cnts_t));
                 break;                  break;
         case CPU_ONLINE:          case CPU_ONLINE:
                 xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0);                  mutex_lock(&mp->m_icsb_mutex);
                 xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0);                  xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0, 0);
                 xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0);                  xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0, 0);
                   xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0, 0);
                   mutex_unlock(&mp->m_icsb_mutex);
                 break;                  break;
         case CPU_DEAD:          case CPU_DEAD:
                 /* Disable all the counters, then fold the dead cpu's                  /* Disable all the counters, then fold the dead cpu's
                  * count into the total on the global superblock and                   * count into the total on the global superblock and
                  * re-enable the counters. */                   * re-enable the counters. */
                   mutex_lock(&mp->m_icsb_mutex);
                 s = XFS_SB_LOCK(mp);                  s = XFS_SB_LOCK(mp);
                 xfs_icsb_disable_counter(mp, XFS_SBS_ICOUNT);                  xfs_icsb_disable_counter(mp, XFS_SBS_ICOUNT);
                 xfs_icsb_disable_counter(mp, XFS_SBS_IFREE);                  xfs_icsb_disable_counter(mp, XFS_SBS_IFREE);
Line 1752  xfs_icsb_cpu_notify( Line 1758  xfs_icsb_cpu_notify(
   
                 memset(cntp, 0, sizeof(xfs_icsb_cnts_t));                  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_ICOUNT,
                 xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, XFS_ICSB_SB_LOCKED);                                           XFS_ICSB_SB_LOCKED, 0);
                 xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, XFS_ICSB_SB_LOCKED);                  xfs_icsb_balance_counter(mp, XFS_SBS_IFREE,
                                            XFS_ICSB_SB_LOCKED, 0);
                   xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS,
                                            XFS_ICSB_SB_LOCKED, 0);
                 XFS_SB_UNLOCK(mp, s);                  XFS_SB_UNLOCK(mp, s);
                   mutex_unlock(&mp->m_icsb_mutex);
                 break;                  break;
         }          }
   
Line 1784  xfs_icsb_init_counters( Line 1794  xfs_icsb_init_counters(
                 cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);                  cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);
                 memset(cntp, 0, sizeof(xfs_icsb_cnts_t));                  memset(cntp, 0, sizeof(xfs_icsb_cnts_t));
         }          }
   
           mutex_init(&mp->m_icsb_mutex);
   
         /*          /*
          * start with all counters disabled so that the           * start with all counters disabled so that the
          * initial balance kicks us off correctly           * initial balance kicks us off correctly
Line 1888  xfs_icsb_disable_counter( Line 1901  xfs_icsb_disable_counter(
   
         ASSERT((field >= XFS_SBS_ICOUNT) && (field <= XFS_SBS_FDBLOCKS));          ASSERT((field >= XFS_SBS_ICOUNT) && (field <= XFS_SBS_FDBLOCKS));
   
           /*
            * If we are already disabled, then there is nothing to do
            * here. We check before locking all the counters to avoid
            * the expensive lock operation when being called in the
            * slow path and the counter is already disabled. This is
            * safe because the only time we set or clear this state is under
            * the m_icsb_mutex.
            */
           if (xfs_icsb_counter_disabled(mp, field))
                   return 0;
   
         xfs_icsb_lock_all_counters(mp);          xfs_icsb_lock_all_counters(mp);
         if (!test_and_set_bit(field, &mp->m_icsb_counters)) {          if (!test_and_set_bit(field, &mp->m_icsb_counters)) {
                 /* drain back to superblock */                  /* drain back to superblock */
Line 1997  xfs_icsb_sync_counters_lazy( Line 2021  xfs_icsb_sync_counters_lazy(
 /*  /*
  * Balance and enable/disable counters as necessary.   * Balance and enable/disable counters as necessary.
  *   *
  * Thresholds for re-enabling counters are somewhat magic.   * Thresholds for re-enabling counters are somewhat magic.  inode counts are
  * inode counts are chosen to be the same number as single   * chosen to be the same number as single on disk allocation chunk per CPU, and
  * on disk allocation chunk per CPU, and free blocks is   * free blocks is something far enough zero that we aren't going thrash when we
  * something far enough zero that we aren't going thrash   * get near ENOSPC. We also need to supply a minimum we require per cpu to
  * when we get near ENOSPC.   * prevent looping endlessly when xfs_alloc_space asks for more than will
    * be distributed to a single CPU but each CPU has enough blocks to be
    * reenabled.
    *
    * Note that we can be called when counters are already disabled.
    * xfs_icsb_disable_counter() optimises the counter locking in this case to
    * prevent locking every per-cpu counter needlessly.
  */   */
 #define XFS_ICSB_INO_CNTR_REENABLE      64  
   #define XFS_ICSB_INO_CNTR_REENABLE      (uint64_t)64
 #define XFS_ICSB_FDBLK_CNTR_REENABLE(mp) \  #define XFS_ICSB_FDBLK_CNTR_REENABLE(mp) \
                 (512 + XFS_ALLOC_SET_ASIDE(mp))                  (uint64_t)(512 + XFS_ALLOC_SET_ASIDE(mp))
 STATIC void  STATIC void
 xfs_icsb_balance_counter(  xfs_icsb_balance_counter(
         xfs_mount_t     *mp,          xfs_mount_t     *mp,
         xfs_sb_field_t  field,          xfs_sb_field_t  field,
         int             flags)          int             flags,
           int             min_per_cpu)
 {  {
         uint64_t        count, resid;          uint64_t        count, resid;
         int             weight = num_online_cpus();          int             weight = num_online_cpus();
         int             s;          int             s;
           uint64_t        min = (uint64_t)min_per_cpu;
   
         if (!(flags & XFS_ICSB_SB_LOCKED))          if (!(flags & XFS_ICSB_SB_LOCKED))
                 s = XFS_SB_LOCK(mp);                  s = XFS_SB_LOCK(mp);
Line 2027  xfs_icsb_balance_counter( Line 2060  xfs_icsb_balance_counter(
         case XFS_SBS_ICOUNT:          case XFS_SBS_ICOUNT:
                 count = mp->m_sb.sb_icount;                  count = mp->m_sb.sb_icount;
                 resid = do_div(count, weight);                  resid = do_div(count, weight);
                 if (count < XFS_ICSB_INO_CNTR_REENABLE)                  if (count < max(min, XFS_ICSB_INO_CNTR_REENABLE))
                         goto out;                          goto out;
                 break;                  break;
         case XFS_SBS_IFREE:          case XFS_SBS_IFREE:
                 count = mp->m_sb.sb_ifree;                  count = mp->m_sb.sb_ifree;
                 resid = do_div(count, weight);                  resid = do_div(count, weight);
                 if (count < XFS_ICSB_INO_CNTR_REENABLE)                  if (count < max(min, XFS_ICSB_INO_CNTR_REENABLE))
                         goto out;                          goto out;
                 break;                  break;
         case XFS_SBS_FDBLOCKS:          case XFS_SBS_FDBLOCKS:
                 count = mp->m_sb.sb_fdblocks;                  count = mp->m_sb.sb_fdblocks;
                 resid = do_div(count, weight);                  resid = do_div(count, weight);
                 if (count < XFS_ICSB_FDBLK_CNTR_REENABLE(mp))                  if (count < max(min, XFS_ICSB_FDBLK_CNTR_REENABLE(mp)))
                         goto out;                          goto out;
                 break;                  break;
         default:          default:
Line 2054  out: Line 2087  out:
                 XFS_SB_UNLOCK(mp, s);                  XFS_SB_UNLOCK(mp, s);
 }  }
   
 STATIC int  int
 xfs_icsb_modify_counters_int(  xfs_icsb_modify_counters(
         xfs_mount_t     *mp,          xfs_mount_t     *mp,
         xfs_sb_field_t  field,          xfs_sb_field_t  field,
         int             delta,          int             delta,
         int             rsvd,          int             rsvd)
         int             flags)  
 {  {
         xfs_icsb_cnts_t *icsbp;          xfs_icsb_cnts_t *icsbp;
         long long       lcounter;       /* long counter for 64 bit fields */          long long       lcounter;       /* long counter for 64 bit fields */
         int             cpu, s, locked = 0;          int             cpu, ret = 0, s;
         int             ret = 0, balance_done = 0;  
   
           might_sleep();
 again:  again:
         cpu = get_cpu();          cpu = get_cpu();
         icsbp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, cpu),          icsbp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, cpu);
         xfs_icsb_lock_cntr(icsbp);  
           /*
            * if the counter is disabled, go to slow path
            */
         if (unlikely(xfs_icsb_counter_disabled(mp, field)))          if (unlikely(xfs_icsb_counter_disabled(mp, field)))
                 goto slow_path;                  goto slow_path;
           xfs_icsb_lock_cntr(icsbp);
           if (unlikely(xfs_icsb_counter_disabled(mp, field))) {
                   xfs_icsb_unlock_cntr(icsbp);
                   goto slow_path;
           }
   
         switch (field) {          switch (field) {
         case XFS_SBS_ICOUNT:          case XFS_SBS_ICOUNT:
                 lcounter = icsbp->icsb_icount;                  lcounter = icsbp->icsb_icount;
                 lcounter += delta;                  lcounter += delta;
                 if (unlikely(lcounter < 0))                  if (unlikely(lcounter < 0))
                         goto slow_path;                          goto balance_counter;
                 icsbp->icsb_icount = lcounter;                  icsbp->icsb_icount = lcounter;
                 break;                  break;
   
Line 2087  again: Line 2127  again:
                 lcounter = icsbp->icsb_ifree;                  lcounter = icsbp->icsb_ifree;
                 lcounter += delta;                  lcounter += delta;
                 if (unlikely(lcounter < 0))                  if (unlikely(lcounter < 0))
                         goto slow_path;                          goto balance_counter;
                 icsbp->icsb_ifree = lcounter;                  icsbp->icsb_ifree = lcounter;
                 break;                  break;
   
Line 2097  again: Line 2137  again:
                 lcounter = icsbp->icsb_fdblocks - XFS_ALLOC_SET_ASIDE(mp);                  lcounter = icsbp->icsb_fdblocks - XFS_ALLOC_SET_ASIDE(mp);
                 lcounter += delta;                  lcounter += delta;
                 if (unlikely(lcounter < 0))                  if (unlikely(lcounter < 0))
                         goto slow_path;                          goto balance_counter;
                 icsbp->icsb_fdblocks = lcounter + XFS_ALLOC_SET_ASIDE(mp);                  icsbp->icsb_fdblocks = lcounter + XFS_ALLOC_SET_ASIDE(mp);
                 break;                  break;
         default:          default:
Line 2106  again: Line 2146  again:
         }          }
         xfs_icsb_unlock_cntr(icsbp);          xfs_icsb_unlock_cntr(icsbp);
         put_cpu();          put_cpu();
         if (locked)  
                 XFS_SB_UNLOCK(mp, s);  
         return 0;          return 0;
   
         /*  
          * The slow path needs to be run with the SBLOCK  
          * held so that we prevent other threads from  
          * attempting to run this path at the same time.  
          * this provides exclusion for the balancing code,  
          * and exclusive fallback if the balance does not  
          * provide enough resources to continue in an unlocked  
          * manner.  
          */  
 slow_path:  slow_path:
         xfs_icsb_unlock_cntr(icsbp);  
         put_cpu();          put_cpu();
   
         /* need to hold superblock incase we need          /*
          * to disable a counter */           * serialise with a mutex so we don't burn lots of cpu on
         if (!(flags & XFS_ICSB_SB_LOCKED)) {           * the superblock lock. We still need to hold the superblock
                 s = XFS_SB_LOCK(mp);           * lock, however, when we modify the global structures.
                 locked = 1;           */
                 flags |= XFS_ICSB_SB_LOCKED;          mutex_lock(&mp->m_icsb_mutex);
         }  
         if (!balance_done) {          /*
                 xfs_icsb_balance_counter(mp, field, flags);           * Now running atomically.
                 balance_done = 1;           *
            * If the counter is enabled, someone has beaten us to rebalancing.
            * Drop the lock and try again in the fast path....
            */
           if (!(xfs_icsb_counter_disabled(mp, field))) {
                   mutex_unlock(&mp->m_icsb_mutex);
                 goto again;                  goto again;
         } else {  
                 /*  
                  * we might not have enough on this local  
                  * cpu to allocate for a bulk request.  
                  * We need to drain this field from all CPUs  
                  * and disable the counter fastpath  
                  */  
                 xfs_icsb_disable_counter(mp, field);  
         }          }
   
           /*
            * The counter is currently disabled. Because we are
            * running atomically here, we know a rebalance cannot
            * be in progress. Hence we can go straight to operating
            * on the global superblock. We do not call xfs_mod_incore_sb()
            * here even though we need to get the SB_LOCK. Doing so
            * will cause us to re-enter this function and deadlock.
            * Hence we get the SB_LOCK ourselves and then call
            * xfs_mod_incore_sb_unlocked() as the unlocked path operates
            * directly on the global counters.
            */
           s = XFS_SB_LOCK(mp);
         ret = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd);          ret = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd);
           XFS_SB_UNLOCK(mp, s);
   
         if (locked)          /*
                 XFS_SB_UNLOCK(mp, s);           * Now that we've modified the global superblock, we
            * may be able to re-enable the distributed counters
            * (e.g. lots of space just got freed). After that
            * we are done.
            */
           if (ret != ENOSPC)
                   xfs_icsb_balance_counter(mp, field, 0, 0);
           mutex_unlock(&mp->m_icsb_mutex);
         return ret;          return ret;
 }  
   
 STATIC int  balance_counter:
 xfs_icsb_modify_counters(          xfs_icsb_unlock_cntr(icsbp);
         xfs_mount_t     *mp,          put_cpu();
         xfs_sb_field_t  field,  
         int             delta,  
         int             rsvd)  
 {  
         return xfs_icsb_modify_counters_int(mp, field, delta, rsvd, 0);  
 }  
   
 /*          /*
  * Called when superblock is already locked           * We may have multiple threads here if multiple per-cpu
  */           * counters run dry at the same time. This will mean we can
 STATIC int           * do more balances than strictly necessary but it is not
 xfs_icsb_modify_counters_locked(           * the common slowpath case.
         xfs_mount_t     *mp,           */
         xfs_sb_field_t  field,          mutex_lock(&mp->m_icsb_mutex);
         int             delta,  
         int             rsvd)          /*
 {           * running atomically.
         return xfs_icsb_modify_counters_int(mp, field, delta,           *
                                                 rsvd, XFS_ICSB_SB_LOCKED);           * This will leave the counter in the correct state for future
            * accesses. After the rebalance, we simply try again and our retry
            * will either succeed through the fast path or slow path without
            * another balance operation being required.
            */
           xfs_icsb_balance_counter(mp, field, 0, delta);
           mutex_unlock(&mp->m_icsb_mutex);
           goto again;
 }  }
   
 #endif  #endif

Removed from v.1.387  
changed lines
  Added in v.1.388


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>