Merge branch 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / fs / xfs / xfs_mount.c
index c04dd83cb57c0b82b812f86c0c717ad220b79bc3..6afaaeb2950abb5c2f15586865789547dfaee6b3 100644 (file)
@@ -200,6 +200,38 @@ xfs_uuid_unmount(
 }
 
 
+/*
+ * Reference counting access wrappers to the perag structures.
+ */
+struct xfs_perag *
+xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno)
+{
+       struct xfs_perag        *pag;
+       int                     ref = 0;
+
+       spin_lock(&mp->m_perag_lock);
+       pag = radix_tree_lookup(&mp->m_perag_tree, agno);
+       if (pag) {
+               ASSERT(atomic_read(&pag->pag_ref) >= 0);
+               /* catch leaks in the positive direction during testing */
+               ASSERT(atomic_read(&pag->pag_ref) < 1000);
+               ref = atomic_inc_return(&pag->pag_ref);
+       }
+       spin_unlock(&mp->m_perag_lock);
+       trace_xfs_perag_get(mp, agno, ref, _RET_IP_);
+       return pag;
+}
+
+void
+xfs_perag_put(struct xfs_perag *pag)
+{
+       int     ref;
+
+       ASSERT(atomic_read(&pag->pag_ref) > 0);
+       ref = atomic_dec_return(&pag->pag_ref);
+       trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_);
+}
+
 /*
  * Free up the resources associated with a mount structure.  Assume that
  * the structure was initially zeroed, so we can tell which fields got
@@ -215,9 +247,9 @@ xfs_free_perag(
        for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
                spin_lock(&mp->m_perag_lock);
                pag = radix_tree_delete(&mp->m_perag_tree, agno);
-               spin_unlock(&mp->m_perag_lock);
                ASSERT(pag);
-               kmem_free(pag->pagb_list);
+               ASSERT(atomic_read(&pag->pag_ref) == 0);
+               spin_unlock(&mp->m_perag_lock);
                kmem_free(pag);
        }
 }
@@ -399,11 +431,13 @@ xfs_initialize_perag(
        xfs_agnumber_t  *maxagi)
 {
        xfs_agnumber_t  index, max_metadata;
+       xfs_agnumber_t  first_initialised = 0;
        xfs_perag_t     *pag;
        xfs_agino_t     agino;
        xfs_ino_t       ino;
        xfs_sb_t        *sbp = &mp->m_sb;
        xfs_ino_t       max_inum = XFS_MAXINUMBER_32;
+       int             error = -ENOMEM;
 
        /* Check to see if the filesystem can overflow 32 bit inodes */
        agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0);
@@ -420,18 +454,23 @@ xfs_initialize_perag(
                        xfs_perag_put(pag);
                        continue;
                }
+               if (!first_initialised)
+                       first_initialised = index;
                pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL);
                if (!pag)
-                       return -ENOMEM;
+                       goto out_unwind;
                if (radix_tree_preload(GFP_NOFS))
-                       return -ENOMEM;
+                       goto out_unwind;
                spin_lock(&mp->m_perag_lock);
                if (radix_tree_insert(&mp->m_perag_tree, index, pag)) {
                        BUG();
                        spin_unlock(&mp->m_perag_lock);
-                       kmem_free(pag);
-                       return -EEXIST;
+                       radix_tree_preload_end();
+                       error = -EEXIST;
+                       goto out_unwind;
                }
+               pag->pag_agno = index;
+               pag->pag_mount = mp;
                spin_unlock(&mp->m_perag_lock);
                radix_tree_preload_end();
        }
@@ -488,6 +527,14 @@ xfs_initialize_perag(
        if (maxagi)
                *maxagi = index;
        return 0;
+
+out_unwind:
+       kmem_free(pag);
+       for (; index > first_initialised; index--) {
+               pag = radix_tree_delete(&mp->m_perag_tree, index);
+               kmem_free(pag);
+       }
+       return error;
 }
 
 void
@@ -618,7 +665,7 @@ xfs_readsb(xfs_mount_t *mp, int flags)
         * access to the superblock.
         */
        sector_size = xfs_getsize_buftarg(mp->m_ddev_targp);
-       extra_flags = XFS_BUF_LOCK | XFS_BUF_MANAGE | XFS_BUF_MAPPED;
+       extra_flags = XBF_LOCK | XBF_FS_MANAGED | XBF_MAPPED;
 
        bp = xfs_buf_read(mp->m_ddev_targp, XFS_SB_DADDR, BTOBB(sector_size),
                          extra_flags);
@@ -1044,6 +1091,22 @@ xfs_mount_reset_sbqflags(
        return xfs_trans_commit(tp, 0);
 }
 
+__uint64_t
+xfs_default_resblks(xfs_mount_t *mp)
+{
+       __uint64_t resblks;
+
+       /*
+        * We default to 5% or 1024 fsbs of space reserved, whichever is smaller.
+        * This may drive us straight to ENOSPC on mount, but that implies
+        * we were already there on the last unmount. Warn if this occurs.
+        */
+       resblks = mp->m_sb.sb_dblocks;
+       do_div(resblks, 20);
+       resblks = min_t(__uint64_t, resblks, 1024);
+       return resblks;
+}
+
 /*
  * This function does the following on an initial mount of a file system:
  *     - reads the superblock from disk and init the mount struct
@@ -1354,18 +1417,14 @@ xfs_mountfs(
         * when at ENOSPC. This is needed for operations like create with
         * attr, unwritten extent conversion at ENOSPC, etc. Data allocations
         * are not allowed to use this reserved space.
-        *
-        * We default to 5% or 1024 fsbs of space reserved, whichever is smaller.
-        * This may drive us straight to ENOSPC on mount, but that implies
-        * we were already there on the last unmount. Warn if this occurs.
         */
-       resblks = mp->m_sb.sb_dblocks;
-       do_div(resblks, 20);
-       resblks = min_t(__uint64_t, resblks, 1024);
-       error = xfs_reserve_blocks(mp, &resblks, NULL);
-       if (error)
-               cmn_err(CE_WARN, "XFS: Unable to allocate reserve blocks. "
-                               "Continuing without a reserve pool.");
+       if (!(mp->m_flags & XFS_MOUNT_RDONLY)) {
+               resblks = xfs_default_resblks(mp);
+               error = xfs_reserve_blocks(mp, &resblks, NULL);
+               if (error)
+                       cmn_err(CE_WARN, "XFS: Unable to allocate reserve "
+                               "blocks. Continuing without a reserve pool.");
+       }
 
        return 0;
 
@@ -1408,8 +1467,19 @@ xfs_unmountfs(
         * push out the iclog we will never get that unlocked. hence we
         * need to force the log first.
         */
-       xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
-       xfs_reclaim_inodes(mp, XFS_IFLUSH_ASYNC);
+       xfs_log_force(mp, XFS_LOG_SYNC);
+
+       /*
+        * Do a delwri reclaim pass first so that as many dirty inodes are
+        * queued up for IO as possible. Then flush the buffers before making
+        * a synchronous path to catch all the remaining inodes are reclaimed.
+        * This makes the reclaim process as quick as possible by avoiding
+        * synchronous writeout and blocking on inodes already in the delwri
+        * state as much as possible.
+        */
+       xfs_reclaim_inodes(mp, 0);
+       XFS_bflush(mp->m_ddev_targp);
+       xfs_reclaim_inodes(mp, SYNC_WAIT);
 
        xfs_qm_unmount(mp);
 
@@ -1418,7 +1488,7 @@ xfs_unmountfs(
         * that nothing is pinned.  This is important because bflush()
         * will skip pinned buffers.
         */
-       xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
+       xfs_log_force(mp, XFS_LOG_SYNC);
 
        xfs_binval(mp->m_ddev_targp);
        if (mp->m_rtdev_targp) {
@@ -1584,15 +1654,14 @@ xfs_mod_sb(xfs_trans_t *tp, __int64_t fields)
        xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, fields);
 
        /* find modified range */
+       f = (xfs_sb_field_t)xfs_highbit64((__uint64_t)fields);
+       ASSERT((1LL << f) & XFS_SB_MOD_BITS);
+       last = xfs_sb_info[f + 1].offset - 1;
 
        f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields);
        ASSERT((1LL << f) & XFS_SB_MOD_BITS);
        first = xfs_sb_info[f].offset;
 
-       f = (xfs_sb_field_t)xfs_highbit64((__uint64_t)fields);
-       ASSERT((1LL << f) & XFS_SB_MOD_BITS);
-       last = xfs_sb_info[f + 1].offset - 1;
-
        xfs_trans_log_buf(tp, bp, first, last);
 }
 
@@ -1923,7 +1992,7 @@ xfs_getsb(
 
        ASSERT(mp->m_sb_bp != NULL);
        bp = mp->m_sb_bp;
-       if (flags & XFS_BUF_TRYLOCK) {
+       if (flags & XBF_TRYLOCK) {
                if (!XFS_BUF_CPSEMA(bp)) {
                        return NULL;
                }