aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2012-06-22 04:50:15 -0400
committerBen Myers <bpm@sgi.com>2012-07-01 15:50:08 -0400
commit9b73bd7b61f320ffe7bda0126592ccf836d7ef90 (patch)
tree2002801ee1d14b9a16487254562a9da2f0d7da71 /fs/xfs
parent1d9025e56143c0c4aebebdb62e46618d3d284218 (diff)
xfs: factor buffer reading from xfs_dir2_leaf_getdents
The buffer reading code in xfs_dir2_leaf_getdents is complex and difficult to follow due to the readahead and all the context is carries. it is also badly indented and so difficult to read. Factor it out into a separate function to make it easier to understand and optimise in future patches. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_dir2_leaf.c434
1 files changed, 232 insertions, 202 deletions
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c
index 69accf6cbc46..0b296253bd01 100644
--- a/fs/xfs/xfs_dir2_leaf.c
+++ b/fs/xfs/xfs_dir2_leaf.c
@@ -759,6 +759,218 @@ xfs_dir2_leaf_compact_x1(
759 *highstalep = highstale; 759 *highstalep = highstale;
760} 760}
761 761
762struct xfs_dir2_leaf_map_info {
763 xfs_extlen_t map_blocks; /* number of fsbs in map */
764 xfs_dablk_t map_off; /* last mapped file offset */
765 int map_size; /* total entries in *map */
766 int map_valid; /* valid entries in *map */
767 int nmap; /* mappings to ask xfs_bmapi */
768 xfs_dir2_db_t curdb; /* db for current block */
769 int ra_current; /* number of read-ahead blks */
770 int ra_index; /* *map index for read-ahead */
771 int ra_offset; /* map entry offset for ra */
772 int ra_want; /* readahead count wanted */
773 struct xfs_bmbt_irec map[]; /* map vector for blocks */
774};
775
776STATIC int
777xfs_dir2_leaf_readbuf(
778 struct xfs_inode *dp,
779 size_t bufsize,
780 struct xfs_dir2_leaf_map_info *mip,
781 xfs_dir2_off_t *curoff,
782 struct xfs_buf **bpp)
783{
784 struct xfs_mount *mp = dp->i_mount;
785 struct xfs_buf *bp = *bpp;
786 struct xfs_bmbt_irec *map = mip->map;
787 int error = 0;
788 int length;
789 int i;
790 int j;
791
792 /*
793 * If we have a buffer, we need to release it and
794 * take it out of the mapping.
795 */
796
797 if (bp) {
798 xfs_trans_brelse(NULL, bp);
799 bp = NULL;
800 mip->map_blocks -= mp->m_dirblkfsbs;
801 /*
802 * Loop to get rid of the extents for the
803 * directory block.
804 */
805 for (i = mp->m_dirblkfsbs; i > 0; ) {
806 j = min_t(int, map->br_blockcount, i);
807 map->br_blockcount -= j;
808 map->br_startblock += j;
809 map->br_startoff += j;
810 /*
811 * If mapping is done, pitch it from
812 * the table.
813 */
814 if (!map->br_blockcount && --mip->map_valid)
815 memmove(&map[0], &map[1],
816 sizeof(map[0]) * mip->map_valid);
817 i -= j;
818 }
819 }
820
821 /*
822 * Recalculate the readahead blocks wanted.
823 */
824 mip->ra_want = howmany(bufsize + mp->m_dirblksize,
825 mp->m_sb.sb_blocksize) - 1;
826 ASSERT(mip->ra_want >= 0);
827
828 /*
829 * If we don't have as many as we want, and we haven't
830 * run out of data blocks, get some more mappings.
831 */
832 if (1 + mip->ra_want > mip->map_blocks &&
833 mip->map_off < xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET)) {
834 /*
835 * Get more bmaps, fill in after the ones
836 * we already have in the table.
837 */
838 mip->nmap = mip->map_size - mip->map_valid;
839 error = xfs_bmapi_read(dp, mip->map_off,
840 xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET) -
841 mip->map_off,
842 &map[mip->map_valid], &mip->nmap, 0);
843
844 /*
845 * Don't know if we should ignore this or try to return an
846 * error. The trouble with returning errors is that readdir
847 * will just stop without actually passing the error through.
848 */
849 if (error)
850 goto out; /* XXX */
851
852 /*
853 * If we got all the mappings we asked for, set the final map
854 * offset based on the last bmap value received. Otherwise,
855 * we've reached the end.
856 */
857 if (mip->nmap == mip->map_size - mip->map_valid) {
858 i = mip->map_valid + mip->nmap - 1;
859 mip->map_off = map[i].br_startoff + map[i].br_blockcount;
860 } else
861 mip->map_off = xfs_dir2_byte_to_da(mp,
862 XFS_DIR2_LEAF_OFFSET);
863
864 /*
865 * Look for holes in the mapping, and eliminate them. Count up
866 * the valid blocks.
867 */
868 for (i = mip->map_valid; i < mip->map_valid + mip->nmap; ) {
869 if (map[i].br_startblock == HOLESTARTBLOCK) {
870 mip->nmap--;
871 length = mip->map_valid + mip->nmap - i;
872 if (length)
873 memmove(&map[i], &map[i + 1],
874 sizeof(map[i]) * length);
875 } else {
876 mip->map_blocks += map[i].br_blockcount;
877 i++;
878 }
879 }
880 mip->map_valid += mip->nmap;
881 }
882
883 /*
884 * No valid mappings, so no more data blocks.
885 */
886 if (!mip->map_valid) {
887 *curoff = xfs_dir2_da_to_byte(mp, mip->map_off);
888 goto out;
889 }
890
891 /*
892 * Read the directory block starting at the first mapping.
893 */
894 mip->curdb = xfs_dir2_da_to_db(mp, map->br_startoff);
895 error = xfs_da_read_buf(NULL, dp, map->br_startoff,
896 map->br_blockcount >= mp->m_dirblkfsbs ?
897 XFS_FSB_TO_DADDR(mp, map->br_startblock) : -1,
898 &bp, XFS_DATA_FORK);
899
900 /*
901 * Should just skip over the data block instead of giving up.
902 */
903 if (error)
904 goto out; /* XXX */
905
906 /*
907 * Adjust the current amount of read-ahead: we just read a block that
908 * was previously ra.
909 */
910 if (mip->ra_current)
911 mip->ra_current -= mp->m_dirblkfsbs;
912
913 /*
914 * Do we need more readahead?
915 */
916 for (mip->ra_index = mip->ra_offset = i = 0;
917 mip->ra_want > mip->ra_current && i < mip->map_blocks;
918 i += mp->m_dirblkfsbs) {
919 ASSERT(mip->ra_index < mip->map_valid);
920 /*
921 * Read-ahead a contiguous directory block.
922 */
923 if (i > mip->ra_current &&
924 map[mip->ra_index].br_blockcount >= mp->m_dirblkfsbs) {
925 xfs_buf_readahead(mp->m_ddev_targp,
926 XFS_FSB_TO_DADDR(mp,
927 map[mip->ra_index].br_startblock +
928 mip->ra_offset),
929 (int)BTOBB(mp->m_dirblksize));
930 mip->ra_current = i;
931 }
932
933 /*
934 * Read-ahead a non-contiguous directory block. This doesn't
935 * use our mapping, but this is a very rare case.
936 */
937 else if (i > mip->ra_current) {
938 xfs_da_reada_buf(NULL, dp,
939 map[mip->ra_index].br_startoff +
940 mip->ra_offset,
941 XFS_DATA_FORK);
942 mip->ra_current = i;
943 }
944
945 /*
946 * Advance offset through the mapping table.
947 */
948 for (j = 0; j < mp->m_dirblkfsbs; j++) {
949 /*
950 * The rest of this extent but not more than a dir
951 * block.
952 */
953 length = min_t(int, mp->m_dirblkfsbs,
954 map[mip->ra_index].br_blockcount -
955 mip->ra_offset);
956 j += length;
957 mip->ra_offset += length;
958
959 /*
960 * Advance to the next mapping if this one is used up.
961 */
962 if (mip->ra_offset == map[mip->ra_index].br_blockcount) {
963 mip->ra_offset = 0;
964 mip->ra_index++;
965 }
966 }
967 }
968
969out:
970 *bpp = bp;
971 return error;
972}
973
762/* 974/*
763 * Getdents (readdir) for leaf and node directories. 975 * Getdents (readdir) for leaf and node directories.
764 * This reads the data blocks only, so is the same for both forms. 976 * This reads the data blocks only, so is the same for both forms.
@@ -771,30 +983,18 @@ xfs_dir2_leaf_getdents(
771 xfs_off_t *offset, 983 xfs_off_t *offset,
772 filldir_t filldir) 984 filldir_t filldir)
773{ 985{
774 struct xfs_buf *bp; /* data block buffer */ 986 struct xfs_buf *bp = NULL; /* data block buffer */
775 int byteoff; /* offset in current block */
776 xfs_dir2_db_t curdb; /* db for current block */
777 xfs_dir2_off_t curoff; /* current overall offset */
778 xfs_dir2_data_hdr_t *hdr; /* data block header */ 987 xfs_dir2_data_hdr_t *hdr; /* data block header */
779 xfs_dir2_data_entry_t *dep; /* data entry */ 988 xfs_dir2_data_entry_t *dep; /* data entry */
780 xfs_dir2_data_unused_t *dup; /* unused entry */ 989 xfs_dir2_data_unused_t *dup; /* unused entry */
781 int error = 0; /* error return value */ 990 int error = 0; /* error return value */
782 int i; /* temporary loop index */
783 int j; /* temporary loop index */
784 int length; /* temporary length value */ 991 int length; /* temporary length value */
785 xfs_bmbt_irec_t *map; /* map vector for blocks */
786 xfs_extlen_t map_blocks; /* number of fsbs in map */
787 xfs_dablk_t map_off; /* last mapped file offset */
788 int map_size; /* total entries in *map */
789 int map_valid; /* valid entries in *map */
790 xfs_mount_t *mp; /* filesystem mount point */ 992 xfs_mount_t *mp; /* filesystem mount point */
993 int byteoff; /* offset in current block */
994 xfs_dir2_off_t curoff; /* current overall offset */
791 xfs_dir2_off_t newoff; /* new curoff after new blk */ 995 xfs_dir2_off_t newoff; /* new curoff after new blk */
792 int nmap; /* mappings to ask xfs_bmapi */
793 char *ptr = NULL; /* pointer to current data */ 996 char *ptr = NULL; /* pointer to current data */
794 int ra_current; /* number of read-ahead blks */ 997 struct xfs_dir2_leaf_map_info *map_info;
795 int ra_index; /* *map index for read-ahead */
796 int ra_offset; /* map entry offset for ra */
797 int ra_want; /* readahead count wanted */
798 998
799 /* 999 /*
800 * If the offset is at or past the largest allowed value, 1000 * If the offset is at or past the largest allowed value,
@@ -810,10 +1010,12 @@ xfs_dir2_leaf_getdents(
810 * buffer size, the directory block size, and the filesystem 1010 * buffer size, the directory block size, and the filesystem
811 * block size. 1011 * block size.
812 */ 1012 */
813 map_size = howmany(bufsize + mp->m_dirblksize, mp->m_sb.sb_blocksize); 1013 length = howmany(bufsize + mp->m_dirblksize,
814 map = kmem_alloc(map_size * sizeof(*map), KM_SLEEP); 1014 mp->m_sb.sb_blocksize);
815 map_valid = ra_index = ra_offset = ra_current = map_blocks = 0; 1015 map_info = kmem_zalloc(offsetof(struct xfs_dir2_leaf_map_info, map) +
816 bp = NULL; 1016 (length * sizeof(struct xfs_bmbt_irec)),
1017 KM_SLEEP);
1018 map_info->map_size = length;
817 1019
818 /* 1020 /*
819 * Inside the loop we keep the main offset value as a byte offset 1021 * Inside the loop we keep the main offset value as a byte offset
@@ -825,7 +1027,9 @@ xfs_dir2_leaf_getdents(
825 * Force this conversion through db so we truncate the offset 1027 * Force this conversion through db so we truncate the offset
826 * down to get the start of the data block. 1028 * down to get the start of the data block.
827 */ 1029 */
828 map_off = xfs_dir2_db_to_da(mp, xfs_dir2_byte_to_db(mp, curoff)); 1030 map_info->map_off = xfs_dir2_db_to_da(mp,
1031 xfs_dir2_byte_to_db(mp, curoff));
1032
829 /* 1033 /*
830 * Loop over directory entries until we reach the end offset. 1034 * Loop over directory entries until we reach the end offset.
831 * Get more blocks and readahead as necessary. 1035 * Get more blocks and readahead as necessary.
@@ -836,190 +1040,16 @@ xfs_dir2_leaf_getdents(
836 * current buffer, need to get another one. 1040 * current buffer, need to get another one.
837 */ 1041 */
838 if (!bp || ptr >= (char *)bp->b_addr + mp->m_dirblksize) { 1042 if (!bp || ptr >= (char *)bp->b_addr + mp->m_dirblksize) {
839 /*
840 * If we have a buffer, we need to release it and
841 * take it out of the mapping.
842 */
843 if (bp) {
844 xfs_trans_brelse(NULL, bp);
845 bp = NULL;
846 map_blocks -= mp->m_dirblkfsbs;
847 /*
848 * Loop to get rid of the extents for the
849 * directory block.
850 */
851 for (i = mp->m_dirblkfsbs; i > 0; ) {
852 j = MIN((int)map->br_blockcount, i);
853 map->br_blockcount -= j;
854 map->br_startblock += j;
855 map->br_startoff += j;
856 /*
857 * If mapping is done, pitch it from
858 * the table.
859 */
860 if (!map->br_blockcount && --map_valid)
861 memmove(&map[0], &map[1],
862 sizeof(map[0]) *
863 map_valid);
864 i -= j;
865 }
866 }
867 /*
868 * Recalculate the readahead blocks wanted.
869 */
870 ra_want = howmany(bufsize + mp->m_dirblksize,
871 mp->m_sb.sb_blocksize) - 1;
872 ASSERT(ra_want >= 0);
873 1043
874 /* 1044 error = xfs_dir2_leaf_readbuf(dp, bufsize, map_info,
875 * If we don't have as many as we want, and we haven't 1045 &curoff, &bp);
876 * run out of data blocks, get some more mappings. 1046 if (error || !map_info->map_valid)
877 */
878 if (1 + ra_want > map_blocks &&
879 map_off <
880 xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET)) {
881 /*
882 * Get more bmaps, fill in after the ones
883 * we already have in the table.
884 */
885 nmap = map_size - map_valid;
886 error = xfs_bmapi_read(dp, map_off,
887 xfs_dir2_byte_to_da(mp,
888 XFS_DIR2_LEAF_OFFSET) - map_off,
889 &map[map_valid], &nmap, 0);
890 /*
891 * Don't know if we should ignore this or
892 * try to return an error.
893 * The trouble with returning errors
894 * is that readdir will just stop without
895 * actually passing the error through.
896 */
897 if (error)
898 break; /* XXX */
899 /*
900 * If we got all the mappings we asked for,
901 * set the final map offset based on the
902 * last bmap value received.
903 * Otherwise, we've reached the end.
904 */
905 if (nmap == map_size - map_valid)
906 map_off =
907 map[map_valid + nmap - 1].br_startoff +
908 map[map_valid + nmap - 1].br_blockcount;
909 else
910 map_off =
911 xfs_dir2_byte_to_da(mp,
912 XFS_DIR2_LEAF_OFFSET);
913 /*
914 * Look for holes in the mapping, and
915 * eliminate them. Count up the valid blocks.
916 */
917 for (i = map_valid; i < map_valid + nmap; ) {
918 if (map[i].br_startblock ==
919 HOLESTARTBLOCK) {
920 nmap--;
921 length = map_valid + nmap - i;
922 if (length)
923 memmove(&map[i],
924 &map[i + 1],
925 sizeof(map[i]) *
926 length);
927 } else {
928 map_blocks +=
929 map[i].br_blockcount;
930 i++;
931 }
932 }
933 map_valid += nmap;
934 }
935 /*
936 * No valid mappings, so no more data blocks.
937 */
938 if (!map_valid) {
939 curoff = xfs_dir2_da_to_byte(mp, map_off);
940 break; 1047 break;
941 } 1048
942 /*
943 * Read the directory block starting at the first
944 * mapping.
945 */
946 curdb = xfs_dir2_da_to_db(mp, map->br_startoff);
947 error = xfs_da_read_buf(NULL, dp, map->br_startoff,
948 map->br_blockcount >= mp->m_dirblkfsbs ?
949 XFS_FSB_TO_DADDR(mp, map->br_startblock) :
950 -1,
951 &bp, XFS_DATA_FORK);
952 /*
953 * Should just skip over the data block instead
954 * of giving up.
955 */
956 if (error)
957 break; /* XXX */
958 /*
959 * Adjust the current amount of read-ahead: we just
960 * read a block that was previously ra.
961 */
962 if (ra_current)
963 ra_current -= mp->m_dirblkfsbs;
964 /*
965 * Do we need more readahead?
966 */
967 for (ra_index = ra_offset = i = 0;
968 ra_want > ra_current && i < map_blocks;
969 i += mp->m_dirblkfsbs) {
970 ASSERT(ra_index < map_valid);
971 /*
972 * Read-ahead a contiguous directory block.
973 */
974 if (i > ra_current &&
975 map[ra_index].br_blockcount >=
976 mp->m_dirblkfsbs) {
977 xfs_buf_readahead(mp->m_ddev_targp,
978 XFS_FSB_TO_DADDR(mp,
979 map[ra_index].br_startblock +
980 ra_offset),
981 (int)BTOBB(mp->m_dirblksize));
982 ra_current = i;
983 }
984 /*
985 * Read-ahead a non-contiguous directory block.
986 * This doesn't use our mapping, but this
987 * is a very rare case.
988 */
989 else if (i > ra_current) {
990 (void)xfs_da_reada_buf(NULL, dp,
991 map[ra_index].br_startoff +
992 ra_offset, XFS_DATA_FORK);
993 ra_current = i;
994 }
995 /*
996 * Advance offset through the mapping table.
997 */
998 for (j = 0; j < mp->m_dirblkfsbs; j++) {
999 /*
1000 * The rest of this extent but not
1001 * more than a dir block.
1002 */
1003 length = MIN(mp->m_dirblkfsbs,
1004 (int)(map[ra_index].br_blockcount -
1005 ra_offset));
1006 j += length;
1007 ra_offset += length;
1008 /*
1009 * Advance to the next mapping if
1010 * this one is used up.
1011 */
1012 if (ra_offset ==
1013 map[ra_index].br_blockcount) {
1014 ra_offset = 0;
1015 ra_index++;
1016 }
1017 }
1018 }
1019 /* 1049 /*
1020 * Having done a read, we need to set a new offset. 1050 * Having done a read, we need to set a new offset.
1021 */ 1051 */
1022 newoff = xfs_dir2_db_off_to_byte(mp, curdb, 0); 1052 newoff = xfs_dir2_db_off_to_byte(mp, map_info->curdb, 0);
1023 /* 1053 /*
1024 * Start of the current block. 1054 * Start of the current block.
1025 */ 1055 */
@@ -1030,7 +1060,7 @@ xfs_dir2_leaf_getdents(
1030 */ 1060 */
1031 else if (curoff > newoff) 1061 else if (curoff > newoff)
1032 ASSERT(xfs_dir2_byte_to_db(mp, curoff) == 1062 ASSERT(xfs_dir2_byte_to_db(mp, curoff) ==
1033 curdb); 1063 map_info->curdb);
1034 hdr = bp->b_addr; 1064 hdr = bp->b_addr;
1035 xfs_dir2_data_check(dp, bp); 1065 xfs_dir2_data_check(dp, bp);
1036 /* 1066 /*
@@ -1113,7 +1143,7 @@ xfs_dir2_leaf_getdents(
1113 *offset = XFS_DIR2_MAX_DATAPTR & 0x7fffffff; 1143 *offset = XFS_DIR2_MAX_DATAPTR & 0x7fffffff;
1114 else 1144 else
1115 *offset = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff; 1145 *offset = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff;
1116 kmem_free(map); 1146 kmem_free(map_info);
1117 if (bp) 1147 if (bp)
1118 xfs_trans_brelse(NULL, bp); 1148 xfs_trans_brelse(NULL, bp);
1119 return error; 1149 return error;