aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Foster <bfoster@redhat.com>2015-08-18 20:01:40 -0400
committerDave Chinner <david@fromorbit.com>2015-08-18 20:01:40 -0400
commitd4a97a04227d5ba91b91888a016e2300861cfbc7 (patch)
tree3f320428898455bdd353f54ef4d8ff65b8786b82
parent146e54b71ea4b998d65c25964807ff6792bbf436 (diff)
xfs: add missing bmap cancel calls in error paths
If a failure occurs after the bmap free list is populated and before xfs_bmap_finish() completes successfully (which returns a partial list on failure), the bmap free list must be cancelled. Otherwise, the extent items on the list are never freed and a memory leak occurs. Several random error paths throughout the code suffer this problem. Fix these up such that xfs_bmap_cancel() is always called on error. Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r--fs/xfs/libxfs/xfs_bmap.c1
-rw-r--r--fs/xfs/xfs_bmap_util.c10
-rw-r--r--fs/xfs/xfs_inode.c9
-rw-r--r--fs/xfs/xfs_rtalloc.c57
4 files changed, 41 insertions, 36 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 63e05b663380..8e2010d53b07 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -5945,6 +5945,7 @@ xfs_bmap_split_extent(
5945 return xfs_trans_commit(tp); 5945 return xfs_trans_commit(tp);
5946 5946
5947out: 5947out:
5948 xfs_bmap_cancel(&free_list);
5948 xfs_trans_cancel(tp); 5949 xfs_trans_cancel(tp);
5949 return error; 5950 return error;
5950} 5951}
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index 73aab0d8d25c..3bf4ad0d19e4 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -1474,7 +1474,7 @@ xfs_shift_file_space(
1474 XFS_DIOSTRAT_SPACE_RES(mp, 0), 0, 1474 XFS_DIOSTRAT_SPACE_RES(mp, 0), 0,
1475 XFS_QMOPT_RES_REGBLKS); 1475 XFS_QMOPT_RES_REGBLKS);
1476 if (error) 1476 if (error)
1477 goto out; 1477 goto out_trans_cancel;
1478 1478
1479 xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); 1479 xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
1480 1480
@@ -1488,18 +1488,20 @@ xfs_shift_file_space(
1488 &done, stop_fsb, &first_block, &free_list, 1488 &done, stop_fsb, &first_block, &free_list,
1489 direction, XFS_BMAP_MAX_SHIFT_EXTENTS); 1489 direction, XFS_BMAP_MAX_SHIFT_EXTENTS);
1490 if (error) 1490 if (error)
1491 goto out; 1491 goto out_bmap_cancel;
1492 1492
1493 error = xfs_bmap_finish(&tp, &free_list, &committed); 1493 error = xfs_bmap_finish(&tp, &free_list, &committed);
1494 if (error) 1494 if (error)
1495 goto out; 1495 goto out_bmap_cancel;
1496 1496
1497 error = xfs_trans_commit(tp); 1497 error = xfs_trans_commit(tp);
1498 } 1498 }
1499 1499
1500 return error; 1500 return error;
1501 1501
1502out: 1502out_bmap_cancel:
1503 xfs_bmap_cancel(&free_list);
1504out_trans_cancel:
1503 xfs_trans_cancel(tp); 1505 xfs_trans_cancel(tp);
1504 return error; 1506 return error;
1505} 1507}
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 3da9f4da4f3d..cee2f69d2469 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1791,14 +1791,15 @@ xfs_inactive_ifree(
1791 xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_ICOUNT, -1); 1791 xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_ICOUNT, -1);
1792 1792
1793 /* 1793 /*
1794 * Just ignore errors at this point. There is nothing we can 1794 * Just ignore errors at this point. There is nothing we can do except
1795 * do except to try to keep going. Make sure it's not a silent 1795 * to try to keep going. Make sure it's not a silent error.
1796 * error.
1797 */ 1796 */
1798 error = xfs_bmap_finish(&tp, &free_list, &committed); 1797 error = xfs_bmap_finish(&tp, &free_list, &committed);
1799 if (error) 1798 if (error) {
1800 xfs_notice(mp, "%s: xfs_bmap_finish returned error %d", 1799 xfs_notice(mp, "%s: xfs_bmap_finish returned error %d",
1801 __func__, error); 1800 __func__, error);
1801 xfs_bmap_cancel(&free_list);
1802 }
1802 error = xfs_trans_commit(tp); 1803 error = xfs_trans_commit(tp);
1803 if (error) 1804 if (error)
1804 xfs_notice(mp, "%s: xfs_trans_commit returned error %d", 1805 xfs_notice(mp, "%s: xfs_trans_commit returned error %d",
diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
index f4e8c06eee26..ab1bac6a3a1c 100644
--- a/fs/xfs/xfs_rtalloc.c
+++ b/fs/xfs/xfs_rtalloc.c
@@ -757,31 +757,30 @@ xfs_rtallocate_extent_size(
757/* 757/*
758 * Allocate space to the bitmap or summary file, and zero it, for growfs. 758 * Allocate space to the bitmap or summary file, and zero it, for growfs.
759 */ 759 */
760STATIC int /* error */ 760STATIC int
761xfs_growfs_rt_alloc( 761xfs_growfs_rt_alloc(
762 xfs_mount_t *mp, /* file system mount point */ 762 struct xfs_mount *mp, /* file system mount point */
763 xfs_extlen_t oblocks, /* old count of blocks */ 763 xfs_extlen_t oblocks, /* old count of blocks */
764 xfs_extlen_t nblocks, /* new count of blocks */ 764 xfs_extlen_t nblocks, /* new count of blocks */
765 xfs_inode_t *ip) /* inode (bitmap/summary) */ 765 struct xfs_inode *ip) /* inode (bitmap/summary) */
766{ 766{
767 xfs_fileoff_t bno; /* block number in file */ 767 xfs_fileoff_t bno; /* block number in file */
768 xfs_buf_t *bp; /* temporary buffer for zeroing */ 768 struct xfs_buf *bp; /* temporary buffer for zeroing */
769 int committed; /* transaction committed flag */ 769 int committed; /* transaction committed flag */
770 xfs_daddr_t d; /* disk block address */ 770 xfs_daddr_t d; /* disk block address */
771 int error; /* error return value */ 771 int error; /* error return value */
772 xfs_fsblock_t firstblock; /* first block allocated in xaction */ 772 xfs_fsblock_t firstblock;/* first block allocated in xaction */
773 xfs_bmap_free_t flist; /* list of freed blocks */ 773 struct xfs_bmap_free flist; /* list of freed blocks */
774 xfs_fsblock_t fsbno; /* filesystem block for bno */ 774 xfs_fsblock_t fsbno; /* filesystem block for bno */
775 xfs_bmbt_irec_t map; /* block map output */ 775 struct xfs_bmbt_irec map; /* block map output */
776 int nmap; /* number of block maps */ 776 int nmap; /* number of block maps */
777 int resblks; /* space reservation */ 777 int resblks; /* space reservation */
778 struct xfs_trans *tp;
778 779
779 /* 780 /*
780 * Allocate space to the file, as necessary. 781 * Allocate space to the file, as necessary.
781 */ 782 */
782 while (oblocks < nblocks) { 783 while (oblocks < nblocks) {
783 xfs_trans_t *tp;
784
785 tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFSRT_ALLOC); 784 tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFSRT_ALLOC);
786 resblks = XFS_GROWFSRT_SPACE_RES(mp, nblocks - oblocks); 785 resblks = XFS_GROWFSRT_SPACE_RES(mp, nblocks - oblocks);
787 /* 786 /*
@@ -790,7 +789,7 @@ xfs_growfs_rt_alloc(
790 error = xfs_trans_reserve(tp, &M_RES(mp)->tr_growrtalloc, 789 error = xfs_trans_reserve(tp, &M_RES(mp)->tr_growrtalloc,
791 resblks, 0); 790 resblks, 0);
792 if (error) 791 if (error)
793 goto error_cancel; 792 goto out_trans_cancel;
794 /* 793 /*
795 * Lock the inode. 794 * Lock the inode.
796 */ 795 */
@@ -808,16 +807,16 @@ xfs_growfs_rt_alloc(
808 if (!error && nmap < 1) 807 if (!error && nmap < 1)
809 error = -ENOSPC; 808 error = -ENOSPC;
810 if (error) 809 if (error)
811 goto error_cancel; 810 goto out_bmap_cancel;
812 /* 811 /*
813 * Free any blocks freed up in the transaction, then commit. 812 * Free any blocks freed up in the transaction, then commit.
814 */ 813 */
815 error = xfs_bmap_finish(&tp, &flist, &committed); 814 error = xfs_bmap_finish(&tp, &flist, &committed);
816 if (error) 815 if (error)
817 goto error_cancel; 816 goto out_bmap_cancel;
818 error = xfs_trans_commit(tp); 817 error = xfs_trans_commit(tp);
819 if (error) 818 if (error)
820 goto error; 819 return error;
821 /* 820 /*
822 * Now we need to clear the allocated blocks. 821 * Now we need to clear the allocated blocks.
823 * Do this one block per transaction, to keep it simple. 822 * Do this one block per transaction, to keep it simple.
@@ -832,7 +831,7 @@ xfs_growfs_rt_alloc(
832 error = xfs_trans_reserve(tp, &M_RES(mp)->tr_growrtzero, 831 error = xfs_trans_reserve(tp, &M_RES(mp)->tr_growrtzero,
833 0, 0); 832 0, 0);
834 if (error) 833 if (error)
835 goto error_cancel; 834 goto out_trans_cancel;
836 /* 835 /*
837 * Lock the bitmap inode. 836 * Lock the bitmap inode.
838 */ 837 */
@@ -846,9 +845,7 @@ xfs_growfs_rt_alloc(
846 mp->m_bsize, 0); 845 mp->m_bsize, 0);
847 if (bp == NULL) { 846 if (bp == NULL) {
848 error = -EIO; 847 error = -EIO;
849error_cancel: 848 goto out_trans_cancel;
850 xfs_trans_cancel(tp);
851 goto error;
852 } 849 }
853 memset(bp->b_addr, 0, mp->m_sb.sb_blocksize); 850 memset(bp->b_addr, 0, mp->m_sb.sb_blocksize);
854 xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1); 851 xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
@@ -857,16 +854,20 @@ error_cancel:
857 */ 854 */
858 error = xfs_trans_commit(tp); 855 error = xfs_trans_commit(tp);
859 if (error) 856 if (error)
860 goto error; 857 return error;
861 } 858 }
862 /* 859 /*
863 * Go on to the next extent, if any. 860 * Go on to the next extent, if any.
864 */ 861 */
865 oblocks = map.br_startoff + map.br_blockcount; 862 oblocks = map.br_startoff + map.br_blockcount;
866 } 863 }
864
867 return 0; 865 return 0;
868 866
869error: 867out_bmap_cancel:
868 xfs_bmap_cancel(&flist);
869out_trans_cancel:
870 xfs_trans_cancel(tp);
870 return error; 871 return error;
871} 872}
872 873