diff options
Diffstat (limited to 'fs/xfs/xfs_file.c')
-rw-r--r-- | fs/xfs/xfs_file.c | 71 |
1 files changed, 19 insertions, 52 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 35703a801372..5fb5a0958a14 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -1043,49 +1043,17 @@ xfs_find_get_desired_pgoff( | |||
1043 | 1043 | ||
1044 | index = startoff >> PAGE_SHIFT; | 1044 | index = startoff >> PAGE_SHIFT; |
1045 | endoff = XFS_FSB_TO_B(mp, map->br_startoff + map->br_blockcount); | 1045 | endoff = XFS_FSB_TO_B(mp, map->br_startoff + map->br_blockcount); |
1046 | end = endoff >> PAGE_SHIFT; | 1046 | end = (endoff - 1) >> PAGE_SHIFT; |
1047 | do { | 1047 | do { |
1048 | int want; | 1048 | int want; |
1049 | unsigned nr_pages; | 1049 | unsigned nr_pages; |
1050 | unsigned int i; | 1050 | unsigned int i; |
1051 | 1051 | ||
1052 | want = min_t(pgoff_t, end - index, PAGEVEC_SIZE); | 1052 | want = min_t(pgoff_t, end - index, PAGEVEC_SIZE - 1) + 1; |
1053 | nr_pages = pagevec_lookup(&pvec, inode->i_mapping, index, | 1053 | nr_pages = pagevec_lookup(&pvec, inode->i_mapping, index, |
1054 | want); | 1054 | want); |
1055 | /* | 1055 | if (nr_pages == 0) |
1056 | * No page mapped into given range. If we are searching holes | ||
1057 | * and if this is the first time we got into the loop, it means | ||
1058 | * that the given offset is landed in a hole, return it. | ||
1059 | * | ||
1060 | * If we have already stepped through some block buffers to find | ||
1061 | * holes but they all contains data. In this case, the last | ||
1062 | * offset is already updated and pointed to the end of the last | ||
1063 | * mapped page, if it does not reach the endpoint to search, | ||
1064 | * that means there should be a hole between them. | ||
1065 | */ | ||
1066 | if (nr_pages == 0) { | ||
1067 | /* Data search found nothing */ | ||
1068 | if (type == DATA_OFF) | ||
1069 | break; | ||
1070 | |||
1071 | ASSERT(type == HOLE_OFF); | ||
1072 | if (lastoff == startoff || lastoff < endoff) { | ||
1073 | found = true; | ||
1074 | *offset = lastoff; | ||
1075 | } | ||
1076 | break; | ||
1077 | } | ||
1078 | |||
1079 | /* | ||
1080 | * At lease we found one page. If this is the first time we | ||
1081 | * step into the loop, and if the first page index offset is | ||
1082 | * greater than the given search offset, a hole was found. | ||
1083 | */ | ||
1084 | if (type == HOLE_OFF && lastoff == startoff && | ||
1085 | lastoff < page_offset(pvec.pages[0])) { | ||
1086 | found = true; | ||
1087 | break; | 1056 | break; |
1088 | } | ||
1089 | 1057 | ||
1090 | for (i = 0; i < nr_pages; i++) { | 1058 | for (i = 0; i < nr_pages; i++) { |
1091 | struct page *page = pvec.pages[i]; | 1059 | struct page *page = pvec.pages[i]; |
@@ -1098,18 +1066,18 @@ xfs_find_get_desired_pgoff( | |||
1098 | * file mapping. However, page->index will not change | 1066 | * file mapping. However, page->index will not change |
1099 | * because we have a reference on the page. | 1067 | * because we have a reference on the page. |
1100 | * | 1068 | * |
1101 | * Searching done if the page index is out of range. | 1069 | * If current page offset is beyond where we've ended, |
1102 | * If the current offset is not reaches the end of | 1070 | * we've found a hole. |
1103 | * the specified search range, there should be a hole | ||
1104 | * between them. | ||
1105 | */ | 1071 | */ |
1106 | if (page->index > end) { | 1072 | if (type == HOLE_OFF && lastoff < endoff && |
1107 | if (type == HOLE_OFF && lastoff < endoff) { | 1073 | lastoff < page_offset(pvec.pages[i])) { |
1108 | *offset = lastoff; | 1074 | found = true; |
1109 | found = true; | 1075 | *offset = lastoff; |
1110 | } | ||
1111 | goto out; | 1076 | goto out; |
1112 | } | 1077 | } |
1078 | /* Searching done if the page index is out of range. */ | ||
1079 | if (page->index > end) | ||
1080 | goto out; | ||
1113 | 1081 | ||
1114 | lock_page(page); | 1082 | lock_page(page); |
1115 | /* | 1083 | /* |
@@ -1151,21 +1119,20 @@ xfs_find_get_desired_pgoff( | |||
1151 | 1119 | ||
1152 | /* | 1120 | /* |
1153 | * The number of returned pages less than our desired, search | 1121 | * The number of returned pages less than our desired, search |
1154 | * done. In this case, nothing was found for searching data, | 1122 | * done. |
1155 | * but we found a hole behind the last offset. | ||
1156 | */ | 1123 | */ |
1157 | if (nr_pages < want) { | 1124 | if (nr_pages < want) |
1158 | if (type == HOLE_OFF) { | ||
1159 | *offset = lastoff; | ||
1160 | found = true; | ||
1161 | } | ||
1162 | break; | 1125 | break; |
1163 | } | ||
1164 | 1126 | ||
1165 | index = pvec.pages[i - 1]->index + 1; | 1127 | index = pvec.pages[i - 1]->index + 1; |
1166 | pagevec_release(&pvec); | 1128 | pagevec_release(&pvec); |
1167 | } while (index <= end); | 1129 | } while (index <= end); |
1168 | 1130 | ||
1131 | /* No page at lastoff and we are not done - we found a hole. */ | ||
1132 | if (type == HOLE_OFF && lastoff < endoff) { | ||
1133 | *offset = lastoff; | ||
1134 | found = true; | ||
1135 | } | ||
1169 | out: | 1136 | out: |
1170 | pagevec_release(&pvec); | 1137 | pagevec_release(&pvec); |
1171 | return found; | 1138 | return found; |