diff options
author | Christoph Hellwig <hch@infradead.org> | 2012-07-04 10:54:50 -0400 |
---|---|---|
committer | Ben Myers <bpm@sgi.com> | 2012-07-29 17:10:54 -0400 |
commit | be60fe54b216a62403b816d3930a66ad7c51cbc6 (patch) | |
tree | 20ae0c5de24e347a42f49a33802de67ff6ee4442 /fs/xfs | |
parent | 55d6af64cb8bf8c7e9a84b254d2c3479be8c067c (diff) |
xfs: do not read the AGI buffer in xfs_dialloc until nessecary
Refactor the AG selection loop in xfs_dialloc to operate on the in-memory
perag data as much as possible. We only read the AGI buffer once we have
selected an AG to allocate inodes now instead of for every AG considered.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r-- | fs/xfs/xfs_ialloc.c | 127 |
1 files changed, 69 insertions, 58 deletions
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index ecb9f22a7f35..21e37b55f7e5 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c | |||
@@ -900,11 +900,10 @@ xfs_dialloc( | |||
900 | struct xfs_mount *mp = tp->t_mountp; | 900 | struct xfs_mount *mp = tp->t_mountp; |
901 | struct xfs_buf *agbp; | 901 | struct xfs_buf *agbp; |
902 | xfs_agnumber_t agno; | 902 | xfs_agnumber_t agno; |
903 | struct xfs_agi *agi; | ||
904 | int error; | 903 | int error; |
905 | int ialloced; | 904 | int ialloced; |
906 | int noroom = 0; | 905 | int noroom = 0; |
907 | xfs_agnumber_t tagno; | 906 | xfs_agnumber_t start_agno; |
908 | struct xfs_perag *pag; | 907 | struct xfs_perag *pag; |
909 | 908 | ||
910 | if (*IO_agbp) { | 909 | if (*IO_agbp) { |
@@ -921,25 +920,17 @@ xfs_dialloc( | |||
921 | * We do not have an agbp, so select an initial allocation | 920 | * We do not have an agbp, so select an initial allocation |
922 | * group for inode allocation. | 921 | * group for inode allocation. |
923 | */ | 922 | */ |
924 | agno = xfs_ialloc_ag_select(tp, parent, mode, okalloc); | 923 | start_agno = xfs_ialloc_ag_select(tp, parent, mode, okalloc); |
925 | if (agno == NULLAGNUMBER) { | 924 | if (start_agno == NULLAGNUMBER) { |
926 | *inop = NULLFSINO; | 925 | *inop = NULLFSINO; |
927 | return 0; | 926 | return 0; |
928 | } | 927 | } |
929 | 928 | ||
930 | error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); | ||
931 | if (error) | ||
932 | return XFS_ERROR(error); | ||
933 | agi = XFS_BUF_TO_AGI(agbp); | ||
934 | |||
935 | tagno = agno; | ||
936 | |||
937 | /* | 929 | /* |
938 | * If we have already hit the ceiling of inode blocks then clear | 930 | * If we have already hit the ceiling of inode blocks then clear |
939 | * okalloc so we scan all available agi structures for a free | 931 | * okalloc so we scan all available agi structures for a free |
940 | * inode. | 932 | * inode. |
941 | */ | 933 | */ |
942 | |||
943 | if (mp->m_maxicount && | 934 | if (mp->m_maxicount && |
944 | mp->m_sb.sb_icount + XFS_IALLOC_INODES(mp) > mp->m_maxicount) { | 935 | mp->m_sb.sb_icount + XFS_IALLOC_INODES(mp) > mp->m_maxicount) { |
945 | noroom = 1; | 936 | noroom = 1; |
@@ -951,67 +942,87 @@ xfs_dialloc( | |||
951 | * or in which we can allocate some inodes. Iterate through the | 942 | * or in which we can allocate some inodes. Iterate through the |
952 | * allocation groups upward, wrapping at the end. | 943 | * allocation groups upward, wrapping at the end. |
953 | */ | 944 | */ |
954 | while (!agi->agi_freecount) { | 945 | agno = start_agno; |
955 | /* | 946 | for (;;) { |
956 | * Don't do anything if we're not supposed to allocate | 947 | pag = xfs_perag_get(mp, agno); |
957 | * any blocks, just go on to the next ag. | 948 | if (!pag->pagi_inodeok) { |
958 | */ | 949 | xfs_ialloc_next_ag(mp); |
959 | if (okalloc) { | 950 | goto nextag; |
960 | /* | 951 | } |
961 | * Try to allocate some new inodes in the allocation | 952 | |
962 | * group. | 953 | if (!pag->pagi_init) { |
963 | */ | 954 | error = xfs_ialloc_pagi_init(mp, tp, agno); |
964 | if ((error = xfs_ialloc_ag_alloc(tp, agbp, &ialloced))) { | 955 | if (error) |
965 | xfs_trans_brelse(tp, agbp); | 956 | goto out_error; |
966 | if (error == ENOSPC) { | ||
967 | *inop = NULLFSINO; | ||
968 | return 0; | ||
969 | } else | ||
970 | return error; | ||
971 | } | ||
972 | if (ialloced) { | ||
973 | /* | ||
974 | * We successfully allocated some inodes, return | ||
975 | * the current context to the caller so that it | ||
976 | * can commit the current transaction and call | ||
977 | * us again where we left off. | ||
978 | */ | ||
979 | ASSERT(be32_to_cpu(agi->agi_freecount) > 0); | ||
980 | *IO_agbp = agbp; | ||
981 | *inop = NULLFSINO; | ||
982 | return 0; | ||
983 | } | ||
984 | } | 957 | } |
958 | |||
985 | /* | 959 | /* |
986 | * If it failed, give up on this ag. | 960 | * Do a first racy fast path check if this AG is usable. |
987 | */ | 961 | */ |
988 | xfs_trans_brelse(tp, agbp); | 962 | if (!pag->pagi_freecount && !okalloc) |
963 | goto nextag; | ||
964 | |||
965 | error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); | ||
966 | if (error) | ||
967 | goto out_error; | ||
968 | |||
989 | /* | 969 | /* |
990 | * Go on to the next ag: get its ag header. | 970 | * Once the AGI has been read in we have to recheck |
971 | * pagi_freecount with the AGI buffer lock held. | ||
991 | */ | 972 | */ |
992 | nextag: | 973 | if (pag->pagi_freecount) { |
993 | if (++tagno == mp->m_sb.sb_agcount) | 974 | xfs_perag_put(pag); |
994 | tagno = 0; | 975 | goto out_alloc; |
995 | if (tagno == agno) { | 976 | } |
977 | |||
978 | if (!okalloc) { | ||
979 | xfs_trans_brelse(tp, agbp); | ||
980 | goto nextag; | ||
981 | } | ||
982 | |||
983 | error = xfs_ialloc_ag_alloc(tp, agbp, &ialloced); | ||
984 | if (error) { | ||
985 | xfs_trans_brelse(tp, agbp); | ||
986 | |||
987 | if (error != ENOSPC) | ||
988 | goto out_error; | ||
989 | |||
990 | xfs_perag_put(pag); | ||
996 | *inop = NULLFSINO; | 991 | *inop = NULLFSINO; |
997 | return noroom ? ENOSPC : 0; | 992 | return 0; |
998 | } | 993 | } |
999 | pag = xfs_perag_get(mp, tagno); | 994 | |
1000 | if (pag->pagi_inodeok == 0) { | 995 | if (ialloced) { |
996 | /* | ||
997 | * We successfully allocated some inodes, return | ||
998 | * the current context to the caller so that it | ||
999 | * can commit the current transaction and call | ||
1000 | * us again where we left off. | ||
1001 | */ | ||
1002 | ASSERT(pag->pagi_freecount > 0); | ||
1001 | xfs_perag_put(pag); | 1003 | xfs_perag_put(pag); |
1002 | goto nextag; | 1004 | |
1005 | *IO_agbp = agbp; | ||
1006 | *inop = NULLFSINO; | ||
1007 | return 0; | ||
1003 | } | 1008 | } |
1004 | error = xfs_ialloc_read_agi(mp, tp, tagno, &agbp); | 1009 | |
1010 | nextag: | ||
1005 | xfs_perag_put(pag); | 1011 | xfs_perag_put(pag); |
1006 | if (error) | 1012 | if (++agno == mp->m_sb.sb_agcount) |
1007 | goto nextag; | 1013 | agno = 0; |
1008 | agi = XFS_BUF_TO_AGI(agbp); | 1014 | if (agno == start_agno) { |
1009 | ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC)); | 1015 | *inop = NULLFSINO; |
1016 | return noroom ? ENOSPC : 0; | ||
1017 | } | ||
1010 | } | 1018 | } |
1011 | 1019 | ||
1012 | out_alloc: | 1020 | out_alloc: |
1013 | *IO_agbp = NULL; | 1021 | *IO_agbp = NULL; |
1014 | return xfs_dialloc_ag(tp, agbp, parent, inop); | 1022 | return xfs_dialloc_ag(tp, agbp, parent, inop); |
1023 | out_error: | ||
1024 | xfs_perag_put(pag); | ||
1025 | return XFS_ERROR(error); | ||
1015 | } | 1026 | } |
1016 | 1027 | ||
1017 | /* | 1028 | /* |