aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Chinner <david@fromorbit.com>2010-01-11 11:47:48 +0000
committerAlex Elder <aelder@sgi.com>2010-01-15 15:34:30 -0600
commit8b26c5825e023b1bccac7afd174ebe55b8905cb1 (patch)
treea8d27401fc943101af7eda72f2ed040664eead68
parentb657fc82a3ca6d7ad16a59e81765f0fb0e86cdbb (diff)
xfs: handle ENOMEM correctly during initialisation of perag structures
Add proper error handling in case an error occurs while initializing new perag structures for a mount point. The mount structure is restored to its previous state by deleting and freeing any perag structures added during the call. Signed-off-by: Dave Chinner <david@fromorbit.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Alex Elder <aelder@sgi.com>
-rw-r--r--fs/xfs/xfs_mount.c21
1 files changed, 17 insertions, 4 deletions
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 049dbc71c28..be643e58806 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -432,11 +432,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);
@@ -453,17 +455,20 @@ 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;
@@ -523,6 +528,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