diff options
author | Brian Foster <bfoster@redhat.com> | 2015-08-18 20:01:40 -0400 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2015-08-18 20:01:40 -0400 |
commit | d4a97a04227d5ba91b91888a016e2300861cfbc7 (patch) | |
tree | 3f320428898455bdd353f54ef4d8ff65b8786b82 | |
parent | 146e54b71ea4b998d65c25964807ff6792bbf436 (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.c | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap_util.c | 10 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.c | 9 | ||||
-rw-r--r-- | fs/xfs/xfs_rtalloc.c | 57 |
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 | ||
5947 | out: | 5947 | out: |
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 | ||
1502 | out: | 1502 | out_bmap_cancel: |
1503 | xfs_bmap_cancel(&free_list); | ||
1504 | out_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 | */ |
760 | STATIC int /* error */ | 760 | STATIC int |
761 | xfs_growfs_rt_alloc( | 761 | xfs_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; |
849 | error_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 | ||
869 | error: | 867 | out_bmap_cancel: |
868 | xfs_bmap_cancel(&flist); | ||
869 | out_trans_cancel: | ||
870 | xfs_trans_cancel(tp); | ||
870 | return error; | 871 | return error; |
871 | } | 872 | } |
872 | 873 | ||