]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
xfs: reallocate realtime summary cache on growfs
authorOmar Sandoval <osandov@fb.com>
Sat, 22 Dec 2018 02:45:18 +0000 (18:45 -0800)
committerDarrick J. Wong <darrick.wong@oracle.com>
Sat, 22 Dec 2018 02:45:18 +0000 (18:45 -0800)
At mount time, we allocate m_rsum_cache with the number of realtime
bitmap blocks. However, xfs_growfs_rt() can increase the number of
realtime bitmap blocks. Using the cache after this happens may access
out of the bounds of the cache. Fix it by reallocating the cache in this
case.

Fixes: 355e3532132b ("xfs: cache minimum realtime summary level")
Signed-off-by: Omar Sandoval <osandov@fb.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
fs/xfs/xfs_rtalloc.c

index afe4d29f7ab4cfa386acad735ac2d05d744d4b3e..ac0fcdad0c4edee1f3085aef91641f2f0a2030ca 100644 (file)
@@ -861,6 +861,21 @@ xfs_growfs_rt_alloc(
        return error;
 }
 
+static void
+xfs_alloc_rsum_cache(
+       xfs_mount_t     *mp,            /* file system mount structure */
+       xfs_extlen_t    rbmblocks)      /* number of rt bitmap blocks */
+{
+       /*
+        * The rsum cache is initialized to all zeroes, which is trivially a
+        * lower bound on the minimum level with any free extents. We can
+        * continue without the cache if it couldn't be allocated.
+        */
+       mp->m_rsum_cache = kmem_zalloc_large(rbmblocks, KM_SLEEP);
+       if (!mp->m_rsum_cache)
+               xfs_warn(mp, "could not allocate realtime summary cache");
+}
+
 /*
  * Visible (exported) functions.
  */
@@ -889,6 +904,7 @@ xfs_growfs_rt(
        xfs_extlen_t    rsumblocks;     /* current number of rt summary blks */
        xfs_sb_t        *sbp;           /* old superblock */
        xfs_fsblock_t   sumbno;         /* summary block number */
+       uint8_t         *rsum_cache;    /* old summary cache */
 
        sbp = &mp->m_sb;
        /*
@@ -945,6 +961,11 @@ xfs_growfs_rt(
        error = xfs_growfs_rt_alloc(mp, rsumblocks, nrsumblocks, mp->m_rsumip);
        if (error)
                return error;
+
+       rsum_cache = mp->m_rsum_cache;
+       if (nrbmblocks != sbp->sb_rbmblocks)
+               xfs_alloc_rsum_cache(mp, nrbmblocks);
+
        /*
         * Allocate a new (fake) mount/sb.
         */
@@ -1070,6 +1091,20 @@ xfs_growfs_rt(
         */
        kmem_free(nmp);
 
+       /*
+        * If we had to allocate a new rsum_cache, we either need to free the
+        * old one (if we succeeded) or free the new one and restore the old one
+        * (if there was an error).
+        */
+       if (rsum_cache != mp->m_rsum_cache) {
+               if (error) {
+                       kmem_free(mp->m_rsum_cache);
+                       mp->m_rsum_cache = rsum_cache;
+               } else {
+                       kmem_free(rsum_cache);
+               }
+       }
+
        return error;
 }
 
@@ -1217,14 +1252,7 @@ xfs_rtmount_inodes(
                return error;
        }
        ASSERT(mp->m_rsumip != NULL);
-       /*
-        * The rsum cache is initialized to all zeroes, which is trivially a
-        * lower bound on the minimum level with any free extents. We can
-        * continue without the cache if it couldn't be allocated.
-        */
-       mp->m_rsum_cache = kmem_zalloc_large(sbp->sb_rbmblocks, KM_SLEEP);
-       if (!mp->m_rsum_cache)
-               xfs_warn(mp, "could not allocate realtime summary cache");
+       xfs_alloc_rsum_cache(mp, sbp->sb_rbmblocks);
        return 0;
 }