diff options
-rw-r--r-- | fs/ntfs/ChangeLog | 4 | ||||
-rw-r--r-- | fs/ntfs/attrib.c | 4 | ||||
-rw-r--r-- | fs/ntfs/mft.c | 12 | ||||
-rw-r--r-- | fs/ntfs/runlist.c | 167 | ||||
-rw-r--r-- | fs/ntfs/runlist.h | 5 |
5 files changed, 132 insertions, 60 deletions
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index aff749db314c..67994c9c248f 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog | |||
@@ -135,6 +135,10 @@ ToDo/Notes: | |||
135 | - Change the runlist terminator of the newly allocated cluster(s) to | 135 | - Change the runlist terminator of the newly allocated cluster(s) to |
136 | LCN_ENOENT in ntfs_attr_make_non_resident(). Otherwise the runlist | 136 | LCN_ENOENT in ntfs_attr_make_non_resident(). Otherwise the runlist |
137 | code gets confused. | 137 | code gets confused. |
138 | - Add an extra parameter @last_vcn to ntfs_get_size_for_mapping_pairs() | ||
139 | and ntfs_mapping_pairs_build() to allow the runlist encoding to be | ||
140 | partial which is desirable when filling holes in sparse attributes. | ||
141 | Update all callers. | ||
138 | 142 | ||
139 | 2.1.22 - Many bug and race fixes and error handling improvements. | 143 | 2.1.22 - Many bug and race fixes and error handling improvements. |
140 | 144 | ||
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 34ea405b883d..c6b2bb64d651 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c | |||
@@ -1317,7 +1317,7 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) | |||
1317 | page = NULL; | 1317 | page = NULL; |
1318 | } | 1318 | } |
1319 | /* Determine the size of the mapping pairs array. */ | 1319 | /* Determine the size of the mapping pairs array. */ |
1320 | mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0); | 1320 | mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0, -1); |
1321 | if (unlikely(mp_size < 0)) { | 1321 | if (unlikely(mp_size < 0)) { |
1322 | err = mp_size; | 1322 | err = mp_size; |
1323 | ntfs_debug("Failed to get size for mapping pairs array, error " | 1323 | ntfs_debug("Failed to get size for mapping pairs array, error " |
@@ -1416,7 +1416,7 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) | |||
1416 | cpu_to_sle64(attr_size); | 1416 | cpu_to_sle64(attr_size); |
1417 | /* Generate the mapping pairs array into the attribute record. */ | 1417 | /* Generate the mapping pairs array into the attribute record. */ |
1418 | err = ntfs_mapping_pairs_build(vol, (u8*)a + mp_ofs, | 1418 | err = ntfs_mapping_pairs_build(vol, (u8*)a + mp_ofs, |
1419 | arec_size - mp_ofs, rl, 0, NULL); | 1419 | arec_size - mp_ofs, rl, 0, -1, NULL); |
1420 | if (unlikely(err)) { | 1420 | if (unlikely(err)) { |
1421 | ntfs_debug("Failed to build mapping pairs, error code %i.", | 1421 | ntfs_debug("Failed to build mapping pairs, error code %i.", |
1422 | err); | 1422 | err); |
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index 61ce09f1b652..3d0ba8e60adc 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c | |||
@@ -1407,7 +1407,7 @@ static int ntfs_mft_bitmap_extend_allocation_nolock(ntfs_volume *vol) | |||
1407 | BUG_ON(ll < rl2->vcn); | 1407 | BUG_ON(ll < rl2->vcn); |
1408 | BUG_ON(ll >= rl2->vcn + rl2->length); | 1408 | BUG_ON(ll >= rl2->vcn + rl2->length); |
1409 | /* Get the size for the new mapping pairs array for this extent. */ | 1409 | /* Get the size for the new mapping pairs array for this extent. */ |
1410 | mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll); | 1410 | mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll, -1); |
1411 | if (unlikely(mp_size <= 0)) { | 1411 | if (unlikely(mp_size <= 0)) { |
1412 | ntfs_error(vol->sb, "Get size for mapping pairs failed for " | 1412 | ntfs_error(vol->sb, "Get size for mapping pairs failed for " |
1413 | "mft bitmap attribute extent."); | 1413 | "mft bitmap attribute extent."); |
@@ -1441,7 +1441,7 @@ static int ntfs_mft_bitmap_extend_allocation_nolock(ntfs_volume *vol) | |||
1441 | /* Generate the mapping pairs array directly into the attr record. */ | 1441 | /* Generate the mapping pairs array directly into the attr record. */ |
1442 | ret = ntfs_mapping_pairs_build(vol, (u8*)a + | 1442 | ret = ntfs_mapping_pairs_build(vol, (u8*)a + |
1443 | le16_to_cpu(a->data.non_resident.mapping_pairs_offset), | 1443 | le16_to_cpu(a->data.non_resident.mapping_pairs_offset), |
1444 | mp_size, rl2, ll, NULL); | 1444 | mp_size, rl2, ll, -1, NULL); |
1445 | if (unlikely(ret)) { | 1445 | if (unlikely(ret)) { |
1446 | ntfs_error(vol->sb, "Failed to build mapping pairs array for " | 1446 | ntfs_error(vol->sb, "Failed to build mapping pairs array for " |
1447 | "mft bitmap attribute."); | 1447 | "mft bitmap attribute."); |
@@ -1529,7 +1529,7 @@ undo_alloc: | |||
1529 | a->data.non_resident.mapping_pairs_offset), | 1529 | a->data.non_resident.mapping_pairs_offset), |
1530 | old_alen - le16_to_cpu( | 1530 | old_alen - le16_to_cpu( |
1531 | a->data.non_resident.mapping_pairs_offset), | 1531 | a->data.non_resident.mapping_pairs_offset), |
1532 | rl2, ll, NULL)) { | 1532 | rl2, ll, -1, NULL)) { |
1533 | ntfs_error(vol->sb, "Failed to restore mapping pairs " | 1533 | ntfs_error(vol->sb, "Failed to restore mapping pairs " |
1534 | "array.%s", es); | 1534 | "array.%s", es); |
1535 | NVolSetErrors(vol); | 1535 | NVolSetErrors(vol); |
@@ -1838,7 +1838,7 @@ static int ntfs_mft_data_extend_allocation_nolock(ntfs_volume *vol) | |||
1838 | BUG_ON(ll < rl2->vcn); | 1838 | BUG_ON(ll < rl2->vcn); |
1839 | BUG_ON(ll >= rl2->vcn + rl2->length); | 1839 | BUG_ON(ll >= rl2->vcn + rl2->length); |
1840 | /* Get the size for the new mapping pairs array for this extent. */ | 1840 | /* Get the size for the new mapping pairs array for this extent. */ |
1841 | mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll); | 1841 | mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll, -1); |
1842 | if (unlikely(mp_size <= 0)) { | 1842 | if (unlikely(mp_size <= 0)) { |
1843 | ntfs_error(vol->sb, "Get size for mapping pairs failed for " | 1843 | ntfs_error(vol->sb, "Get size for mapping pairs failed for " |
1844 | "mft data attribute extent."); | 1844 | "mft data attribute extent."); |
@@ -1877,7 +1877,7 @@ static int ntfs_mft_data_extend_allocation_nolock(ntfs_volume *vol) | |||
1877 | /* Generate the mapping pairs array directly into the attr record. */ | 1877 | /* Generate the mapping pairs array directly into the attr record. */ |
1878 | ret = ntfs_mapping_pairs_build(vol, (u8*)a + | 1878 | ret = ntfs_mapping_pairs_build(vol, (u8*)a + |
1879 | le16_to_cpu(a->data.non_resident.mapping_pairs_offset), | 1879 | le16_to_cpu(a->data.non_resident.mapping_pairs_offset), |
1880 | mp_size, rl2, ll, NULL); | 1880 | mp_size, rl2, ll, -1, NULL); |
1881 | if (unlikely(ret)) { | 1881 | if (unlikely(ret)) { |
1882 | ntfs_error(vol->sb, "Failed to build mapping pairs array of " | 1882 | ntfs_error(vol->sb, "Failed to build mapping pairs array of " |
1883 | "mft data attribute."); | 1883 | "mft data attribute."); |
@@ -1959,7 +1959,7 @@ undo_alloc: | |||
1959 | a->data.non_resident.mapping_pairs_offset), | 1959 | a->data.non_resident.mapping_pairs_offset), |
1960 | old_alen - le16_to_cpu( | 1960 | old_alen - le16_to_cpu( |
1961 | a->data.non_resident.mapping_pairs_offset), | 1961 | a->data.non_resident.mapping_pairs_offset), |
1962 | rl2, ll, NULL)) { | 1962 | rl2, ll, -1, NULL)) { |
1963 | ntfs_error(vol->sb, "Failed to restore mapping pairs " | 1963 | ntfs_error(vol->sb, "Failed to restore mapping pairs " |
1964 | "array.%s", es); | 1964 | "array.%s", es); |
1965 | NVolSetErrors(vol); | 1965 | NVolSetErrors(vol); |
diff --git a/fs/ntfs/runlist.c b/fs/ntfs/runlist.c index 396d767c2cab..758855b0414e 100644 --- a/fs/ntfs/runlist.c +++ b/fs/ntfs/runlist.c | |||
@@ -1048,10 +1048,17 @@ static inline int ntfs_get_nr_significant_bytes(const s64 n) | |||
1048 | * ntfs_get_size_for_mapping_pairs - get bytes needed for mapping pairs array | 1048 | * ntfs_get_size_for_mapping_pairs - get bytes needed for mapping pairs array |
1049 | * @vol: ntfs volume (needed for the ntfs version) | 1049 | * @vol: ntfs volume (needed for the ntfs version) |
1050 | * @rl: locked runlist to determine the size of the mapping pairs of | 1050 | * @rl: locked runlist to determine the size of the mapping pairs of |
1051 | * @start_vcn: vcn at which to start the mapping pairs array | 1051 | * @first_vcn: first vcn which to include in the mapping pairs array |
1052 | * @last_vcn: last vcn which to include in the mapping pairs array | ||
1052 | * | 1053 | * |
1053 | * Walk the locked runlist @rl and calculate the size in bytes of the mapping | 1054 | * Walk the locked runlist @rl and calculate the size in bytes of the mapping |
1054 | * pairs array corresponding to the runlist @rl, starting at vcn @start_vcn. | 1055 | * pairs array corresponding to the runlist @rl, starting at vcn @first_vcn and |
1056 | * finishing with vcn @last_vcn. | ||
1057 | * | ||
1058 | * A @last_vcn of -1 means end of runlist and in that case the size of the | ||
1059 | * mapping pairs array corresponding to the runlist starting at vcn @first_vcn | ||
1060 | * and finishing at the end of the runlist is determined. | ||
1061 | * | ||
1055 | * This for example allows us to allocate a buffer of the right size when | 1062 | * This for example allows us to allocate a buffer of the right size when |
1056 | * building the mapping pairs array. | 1063 | * building the mapping pairs array. |
1057 | * | 1064 | * |
@@ -1067,34 +1074,50 @@ static inline int ntfs_get_nr_significant_bytes(const s64 n) | |||
1067 | * remains locked throughout, and is left locked upon return. | 1074 | * remains locked throughout, and is left locked upon return. |
1068 | */ | 1075 | */ |
1069 | int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol, | 1076 | int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol, |
1070 | const runlist_element *rl, const VCN start_vcn) | 1077 | const runlist_element *rl, const VCN first_vcn, |
1078 | const VCN last_vcn) | ||
1071 | { | 1079 | { |
1072 | LCN prev_lcn; | 1080 | LCN prev_lcn; |
1073 | int rls; | 1081 | int rls; |
1082 | BOOL the_end = FALSE; | ||
1074 | 1083 | ||
1075 | BUG_ON(start_vcn < 0); | 1084 | BUG_ON(first_vcn < 0); |
1085 | BUG_ON(last_vcn < -1); | ||
1086 | BUG_ON(last_vcn >= 0 && first_vcn > last_vcn); | ||
1076 | if (!rl) { | 1087 | if (!rl) { |
1077 | BUG_ON(start_vcn); | 1088 | BUG_ON(first_vcn); |
1089 | BUG_ON(last_vcn > 0); | ||
1078 | return 1; | 1090 | return 1; |
1079 | } | 1091 | } |
1080 | /* Skip to runlist element containing @start_vcn. */ | 1092 | /* Skip to runlist element containing @first_vcn. */ |
1081 | while (rl->length && start_vcn >= rl[1].vcn) | 1093 | while (rl->length && first_vcn >= rl[1].vcn) |
1082 | rl++; | 1094 | rl++; |
1083 | if ((!rl->length && start_vcn > rl->vcn) || start_vcn < rl->vcn) | 1095 | if (unlikely((!rl->length && first_vcn > rl->vcn) || |
1096 | first_vcn < rl->vcn)) | ||
1084 | return -EINVAL; | 1097 | return -EINVAL; |
1085 | prev_lcn = 0; | 1098 | prev_lcn = 0; |
1086 | /* Always need the termining zero byte. */ | 1099 | /* Always need the termining zero byte. */ |
1087 | rls = 1; | 1100 | rls = 1; |
1088 | /* Do the first partial run if present. */ | 1101 | /* Do the first partial run if present. */ |
1089 | if (start_vcn > rl->vcn) { | 1102 | if (first_vcn > rl->vcn) { |
1090 | s64 delta; | 1103 | s64 delta, length = rl->length; |
1091 | 1104 | ||
1092 | /* We know rl->length != 0 already. */ | 1105 | /* We know rl->length != 0 already. */ |
1093 | if (rl->length < 0 || rl->lcn < LCN_HOLE) | 1106 | if (unlikely(length < 0 || rl->lcn < LCN_HOLE)) |
1094 | goto err_out; | 1107 | goto err_out; |
1095 | delta = start_vcn - rl->vcn; | 1108 | /* |
1109 | * If @stop_vcn is given and finishes inside this run, cap the | ||
1110 | * run length. | ||
1111 | */ | ||
1112 | if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) { | ||
1113 | s64 s1 = last_vcn + 1; | ||
1114 | if (unlikely(rl[1].vcn > s1)) | ||
1115 | length = s1 - rl->vcn; | ||
1116 | the_end = TRUE; | ||
1117 | } | ||
1118 | delta = first_vcn - rl->vcn; | ||
1096 | /* Header byte + length. */ | 1119 | /* Header byte + length. */ |
1097 | rls += 1 + ntfs_get_nr_significant_bytes(rl->length - delta); | 1120 | rls += 1 + ntfs_get_nr_significant_bytes(length - delta); |
1098 | /* | 1121 | /* |
1099 | * If the logical cluster number (lcn) denotes a hole and we | 1122 | * If the logical cluster number (lcn) denotes a hole and we |
1100 | * are on NTFS 3.0+, we don't store it at all, i.e. we need | 1123 | * are on NTFS 3.0+, we don't store it at all, i.e. we need |
@@ -1102,9 +1125,9 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol, | |||
1102 | * Note: this assumes that on NTFS 1.2-, holes are stored with | 1125 | * Note: this assumes that on NTFS 1.2-, holes are stored with |
1103 | * an lcn of -1 and not a delta_lcn of -1 (unless both are -1). | 1126 | * an lcn of -1 and not a delta_lcn of -1 (unless both are -1). |
1104 | */ | 1127 | */ |
1105 | if (rl->lcn >= 0 || vol->major_ver < 3) { | 1128 | if (likely(rl->lcn >= 0 || vol->major_ver < 3)) { |
1106 | prev_lcn = rl->lcn; | 1129 | prev_lcn = rl->lcn; |
1107 | if (rl->lcn >= 0) | 1130 | if (likely(rl->lcn >= 0)) |
1108 | prev_lcn += delta; | 1131 | prev_lcn += delta; |
1109 | /* Change in lcn. */ | 1132 | /* Change in lcn. */ |
1110 | rls += ntfs_get_nr_significant_bytes(prev_lcn); | 1133 | rls += ntfs_get_nr_significant_bytes(prev_lcn); |
@@ -1113,11 +1136,23 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol, | |||
1113 | rl++; | 1136 | rl++; |
1114 | } | 1137 | } |
1115 | /* Do the full runs. */ | 1138 | /* Do the full runs. */ |
1116 | for (; rl->length; rl++) { | 1139 | for (; rl->length && !the_end; rl++) { |
1117 | if (rl->length < 0 || rl->lcn < LCN_HOLE) | 1140 | s64 length = rl->length; |
1141 | |||
1142 | if (unlikely(length < 0 || rl->lcn < LCN_HOLE)) | ||
1118 | goto err_out; | 1143 | goto err_out; |
1144 | /* | ||
1145 | * If @stop_vcn is given and finishes inside this run, cap the | ||
1146 | * run length. | ||
1147 | */ | ||
1148 | if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) { | ||
1149 | s64 s1 = last_vcn + 1; | ||
1150 | if (unlikely(rl[1].vcn > s1)) | ||
1151 | length = s1 - rl->vcn; | ||
1152 | the_end = TRUE; | ||
1153 | } | ||
1119 | /* Header byte + length. */ | 1154 | /* Header byte + length. */ |
1120 | rls += 1 + ntfs_get_nr_significant_bytes(rl->length); | 1155 | rls += 1 + ntfs_get_nr_significant_bytes(length); |
1121 | /* | 1156 | /* |
1122 | * If the logical cluster number (lcn) denotes a hole and we | 1157 | * If the logical cluster number (lcn) denotes a hole and we |
1123 | * are on NTFS 3.0+, we don't store it at all, i.e. we need | 1158 | * are on NTFS 3.0+, we don't store it at all, i.e. we need |
@@ -1125,7 +1160,7 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol, | |||
1125 | * Note: this assumes that on NTFS 1.2-, holes are stored with | 1160 | * Note: this assumes that on NTFS 1.2-, holes are stored with |
1126 | * an lcn of -1 and not a delta_lcn of -1 (unless both are -1). | 1161 | * an lcn of -1 and not a delta_lcn of -1 (unless both are -1). |
1127 | */ | 1162 | */ |
1128 | if (rl->lcn >= 0 || vol->major_ver < 3) { | 1163 | if (likely(rl->lcn >= 0 || vol->major_ver < 3)) { |
1129 | /* Change in lcn. */ | 1164 | /* Change in lcn. */ |
1130 | rls += ntfs_get_nr_significant_bytes(rl->lcn - | 1165 | rls += ntfs_get_nr_significant_bytes(rl->lcn - |
1131 | prev_lcn); | 1166 | prev_lcn); |
@@ -1168,7 +1203,7 @@ static inline int ntfs_write_significant_bytes(s8 *dst, const s8 *dst_max, | |||
1168 | 1203 | ||
1169 | i = 0; | 1204 | i = 0; |
1170 | do { | 1205 | do { |
1171 | if (dst > dst_max) | 1206 | if (unlikely(dst > dst_max)) |
1172 | goto err_out; | 1207 | goto err_out; |
1173 | *dst++ = l & 0xffll; | 1208 | *dst++ = l & 0xffll; |
1174 | l >>= 8; | 1209 | l >>= 8; |
@@ -1177,12 +1212,12 @@ static inline int ntfs_write_significant_bytes(s8 *dst, const s8 *dst_max, | |||
1177 | j = (n >> 8 * (i - 1)) & 0xff; | 1212 | j = (n >> 8 * (i - 1)) & 0xff; |
1178 | /* If the sign bit is wrong, we need an extra byte. */ | 1213 | /* If the sign bit is wrong, we need an extra byte. */ |
1179 | if (n < 0 && j >= 0) { | 1214 | if (n < 0 && j >= 0) { |
1180 | if (dst > dst_max) | 1215 | if (unlikely(dst > dst_max)) |
1181 | goto err_out; | 1216 | goto err_out; |
1182 | i++; | 1217 | i++; |
1183 | *dst = (s8)-1; | 1218 | *dst = (s8)-1; |
1184 | } else if (n > 0 && j < 0) { | 1219 | } else if (n > 0 && j < 0) { |
1185 | if (dst > dst_max) | 1220 | if (unlikely(dst > dst_max)) |
1186 | goto err_out; | 1221 | goto err_out; |
1187 | i++; | 1222 | i++; |
1188 | *dst = (s8)0; | 1223 | *dst = (s8)0; |
@@ -1198,13 +1233,18 @@ err_out: | |||
1198 | * @dst: destination buffer to which to write the mapping pairs array | 1233 | * @dst: destination buffer to which to write the mapping pairs array |
1199 | * @dst_len: size of destination buffer @dst in bytes | 1234 | * @dst_len: size of destination buffer @dst in bytes |
1200 | * @rl: locked runlist for which to build the mapping pairs array | 1235 | * @rl: locked runlist for which to build the mapping pairs array |
1201 | * @start_vcn: vcn at which to start the mapping pairs array | 1236 | * @first_vcn: first vcn which to include in the mapping pairs array |
1237 | * @last_vcn: last vcn which to include in the mapping pairs array | ||
1202 | * @stop_vcn: first vcn outside destination buffer on success or -ENOSPC | 1238 | * @stop_vcn: first vcn outside destination buffer on success or -ENOSPC |
1203 | * | 1239 | * |
1204 | * Create the mapping pairs array from the locked runlist @rl, starting at vcn | 1240 | * Create the mapping pairs array from the locked runlist @rl, starting at vcn |
1205 | * @start_vcn and save the array in @dst. @dst_len is the size of @dst in | 1241 | * @first_vcn and finishing with vcn @last_vcn and save the array in @dst. |
1206 | * bytes and it should be at least equal to the value obtained by calling | 1242 | * @dst_len is the size of @dst in bytes and it should be at least equal to the |
1207 | * ntfs_get_size_for_mapping_pairs(). | 1243 | * value obtained by calling ntfs_get_size_for_mapping_pairs(). |
1244 | * | ||
1245 | * A @last_vcn of -1 means end of runlist and in that case the mapping pairs | ||
1246 | * array corresponding to the runlist starting at vcn @first_vcn and finishing | ||
1247 | * at the end of the runlist is created. | ||
1208 | * | 1248 | * |
1209 | * If @rl is NULL, just write a single terminator byte to @dst. | 1249 | * If @rl is NULL, just write a single terminator byte to @dst. |
1210 | * | 1250 | * |
@@ -1213,7 +1253,7 @@ err_out: | |||
1213 | * been filled with all the mapping pairs that will fit, thus it can be treated | 1253 | * been filled with all the mapping pairs that will fit, thus it can be treated |
1214 | * as partial success, in that a new attribute extent needs to be created or | 1254 | * as partial success, in that a new attribute extent needs to be created or |
1215 | * the next extent has to be used and the mapping pairs build has to be | 1255 | * the next extent has to be used and the mapping pairs build has to be |
1216 | * continued with @start_vcn set to *@stop_vcn. | 1256 | * continued with @first_vcn set to *@stop_vcn. |
1217 | * | 1257 | * |
1218 | * Return 0 on success and -errno on error. The following error codes are | 1258 | * Return 0 on success and -errno on error. The following error codes are |
1219 | * defined: | 1259 | * defined: |
@@ -1227,27 +1267,32 @@ err_out: | |||
1227 | */ | 1267 | */ |
1228 | int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst, | 1268 | int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst, |
1229 | const int dst_len, const runlist_element *rl, | 1269 | const int dst_len, const runlist_element *rl, |
1230 | const VCN start_vcn, VCN *const stop_vcn) | 1270 | const VCN first_vcn, const VCN last_vcn, VCN *const stop_vcn) |
1231 | { | 1271 | { |
1232 | LCN prev_lcn; | 1272 | LCN prev_lcn; |
1233 | s8 *dst_max, *dst_next; | 1273 | s8 *dst_max, *dst_next; |
1234 | int err = -ENOSPC; | 1274 | int err = -ENOSPC; |
1275 | BOOL the_end = FALSE; | ||
1235 | s8 len_len, lcn_len; | 1276 | s8 len_len, lcn_len; |
1236 | 1277 | ||
1237 | BUG_ON(start_vcn < 0); | 1278 | BUG_ON(first_vcn < 0); |
1279 | BUG_ON(last_vcn < -1); | ||
1280 | BUG_ON(last_vcn >= 0 && first_vcn > last_vcn); | ||
1238 | BUG_ON(dst_len < 1); | 1281 | BUG_ON(dst_len < 1); |
1239 | if (!rl) { | 1282 | if (!rl) { |
1240 | BUG_ON(start_vcn); | 1283 | BUG_ON(first_vcn); |
1284 | BUG_ON(last_vcn > 0); | ||
1241 | if (stop_vcn) | 1285 | if (stop_vcn) |
1242 | *stop_vcn = 0; | 1286 | *stop_vcn = 0; |
1243 | /* Terminator byte. */ | 1287 | /* Terminator byte. */ |
1244 | *dst = 0; | 1288 | *dst = 0; |
1245 | return 0; | 1289 | return 0; |
1246 | } | 1290 | } |
1247 | /* Skip to runlist element containing @start_vcn. */ | 1291 | /* Skip to runlist element containing @first_vcn. */ |
1248 | while (rl->length && start_vcn >= rl[1].vcn) | 1292 | while (rl->length && first_vcn >= rl[1].vcn) |
1249 | rl++; | 1293 | rl++; |
1250 | if ((!rl->length && start_vcn > rl->vcn) || start_vcn < rl->vcn) | 1294 | if (unlikely((!rl->length && first_vcn > rl->vcn) || |
1295 | first_vcn < rl->vcn)) | ||
1251 | return -EINVAL; | 1296 | return -EINVAL; |
1252 | /* | 1297 | /* |
1253 | * @dst_max is used for bounds checking in | 1298 | * @dst_max is used for bounds checking in |
@@ -1256,17 +1301,27 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst, | |||
1256 | dst_max = dst + dst_len - 1; | 1301 | dst_max = dst + dst_len - 1; |
1257 | prev_lcn = 0; | 1302 | prev_lcn = 0; |
1258 | /* Do the first partial run if present. */ | 1303 | /* Do the first partial run if present. */ |
1259 | if (start_vcn > rl->vcn) { | 1304 | if (first_vcn > rl->vcn) { |
1260 | s64 delta; | 1305 | s64 delta, length = rl->length; |
1261 | 1306 | ||
1262 | /* We know rl->length != 0 already. */ | 1307 | /* We know rl->length != 0 already. */ |
1263 | if (rl->length < 0 || rl->lcn < LCN_HOLE) | 1308 | if (unlikely(length < 0 || rl->lcn < LCN_HOLE)) |
1264 | goto err_out; | 1309 | goto err_out; |
1265 | delta = start_vcn - rl->vcn; | 1310 | /* |
1311 | * If @stop_vcn is given and finishes inside this run, cap the | ||
1312 | * run length. | ||
1313 | */ | ||
1314 | if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) { | ||
1315 | s64 s1 = last_vcn + 1; | ||
1316 | if (unlikely(rl[1].vcn > s1)) | ||
1317 | length = s1 - rl->vcn; | ||
1318 | the_end = TRUE; | ||
1319 | } | ||
1320 | delta = first_vcn - rl->vcn; | ||
1266 | /* Write length. */ | 1321 | /* Write length. */ |
1267 | len_len = ntfs_write_significant_bytes(dst + 1, dst_max, | 1322 | len_len = ntfs_write_significant_bytes(dst + 1, dst_max, |
1268 | rl->length - delta); | 1323 | length - delta); |
1269 | if (len_len < 0) | 1324 | if (unlikely(len_len < 0)) |
1270 | goto size_err; | 1325 | goto size_err; |
1271 | /* | 1326 | /* |
1272 | * If the logical cluster number (lcn) denotes a hole and we | 1327 | * If the logical cluster number (lcn) denotes a hole and we |
@@ -1277,19 +1332,19 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst, | |||
1277 | * case on NT4. - We assume that we just need to write the lcn | 1332 | * case on NT4. - We assume that we just need to write the lcn |
1278 | * change until someone tells us otherwise... (AIA) | 1333 | * change until someone tells us otherwise... (AIA) |
1279 | */ | 1334 | */ |
1280 | if (rl->lcn >= 0 || vol->major_ver < 3) { | 1335 | if (likely(rl->lcn >= 0 || vol->major_ver < 3)) { |
1281 | prev_lcn = rl->lcn; | 1336 | prev_lcn = rl->lcn; |
1282 | if (rl->lcn >= 0) | 1337 | if (likely(rl->lcn >= 0)) |
1283 | prev_lcn += delta; | 1338 | prev_lcn += delta; |
1284 | /* Write change in lcn. */ | 1339 | /* Write change in lcn. */ |
1285 | lcn_len = ntfs_write_significant_bytes(dst + 1 + | 1340 | lcn_len = ntfs_write_significant_bytes(dst + 1 + |
1286 | len_len, dst_max, prev_lcn); | 1341 | len_len, dst_max, prev_lcn); |
1287 | if (lcn_len < 0) | 1342 | if (unlikely(lcn_len < 0)) |
1288 | goto size_err; | 1343 | goto size_err; |
1289 | } else | 1344 | } else |
1290 | lcn_len = 0; | 1345 | lcn_len = 0; |
1291 | dst_next = dst + len_len + lcn_len + 1; | 1346 | dst_next = dst + len_len + lcn_len + 1; |
1292 | if (dst_next > dst_max) | 1347 | if (unlikely(dst_next > dst_max)) |
1293 | goto size_err; | 1348 | goto size_err; |
1294 | /* Update header byte. */ | 1349 | /* Update header byte. */ |
1295 | *dst = lcn_len << 4 | len_len; | 1350 | *dst = lcn_len << 4 | len_len; |
@@ -1299,13 +1354,25 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst, | |||
1299 | rl++; | 1354 | rl++; |
1300 | } | 1355 | } |
1301 | /* Do the full runs. */ | 1356 | /* Do the full runs. */ |
1302 | for (; rl->length; rl++) { | 1357 | for (; rl->length && !the_end; rl++) { |
1303 | if (rl->length < 0 || rl->lcn < LCN_HOLE) | 1358 | s64 length = rl->length; |
1359 | |||
1360 | if (unlikely(length < 0 || rl->lcn < LCN_HOLE)) | ||
1304 | goto err_out; | 1361 | goto err_out; |
1362 | /* | ||
1363 | * If @stop_vcn is given and finishes inside this run, cap the | ||
1364 | * run length. | ||
1365 | */ | ||
1366 | if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) { | ||
1367 | s64 s1 = last_vcn + 1; | ||
1368 | if (unlikely(rl[1].vcn > s1)) | ||
1369 | length = s1 - rl->vcn; | ||
1370 | the_end = TRUE; | ||
1371 | } | ||
1305 | /* Write length. */ | 1372 | /* Write length. */ |
1306 | len_len = ntfs_write_significant_bytes(dst + 1, dst_max, | 1373 | len_len = ntfs_write_significant_bytes(dst + 1, dst_max, |
1307 | rl->length); | 1374 | length); |
1308 | if (len_len < 0) | 1375 | if (unlikely(len_len < 0)) |
1309 | goto size_err; | 1376 | goto size_err; |
1310 | /* | 1377 | /* |
1311 | * If the logical cluster number (lcn) denotes a hole and we | 1378 | * If the logical cluster number (lcn) denotes a hole and we |
@@ -1316,17 +1383,17 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst, | |||
1316 | * case on NT4. - We assume that we just need to write the lcn | 1383 | * case on NT4. - We assume that we just need to write the lcn |
1317 | * change until someone tells us otherwise... (AIA) | 1384 | * change until someone tells us otherwise... (AIA) |
1318 | */ | 1385 | */ |
1319 | if (rl->lcn >= 0 || vol->major_ver < 3) { | 1386 | if (likely(rl->lcn >= 0 || vol->major_ver < 3)) { |
1320 | /* Write change in lcn. */ | 1387 | /* Write change in lcn. */ |
1321 | lcn_len = ntfs_write_significant_bytes(dst + 1 + | 1388 | lcn_len = ntfs_write_significant_bytes(dst + 1 + |
1322 | len_len, dst_max, rl->lcn - prev_lcn); | 1389 | len_len, dst_max, rl->lcn - prev_lcn); |
1323 | if (lcn_len < 0) | 1390 | if (unlikely(lcn_len < 0)) |
1324 | goto size_err; | 1391 | goto size_err; |
1325 | prev_lcn = rl->lcn; | 1392 | prev_lcn = rl->lcn; |
1326 | } else | 1393 | } else |
1327 | lcn_len = 0; | 1394 | lcn_len = 0; |
1328 | dst_next = dst + len_len + lcn_len + 1; | 1395 | dst_next = dst + len_len + lcn_len + 1; |
1329 | if (dst_next > dst_max) | 1396 | if (unlikely(dst_next > dst_max)) |
1330 | goto size_err; | 1397 | goto size_err; |
1331 | /* Update header byte. */ | 1398 | /* Update header byte. */ |
1332 | *dst = lcn_len << 4 | len_len; | 1399 | *dst = lcn_len << 4 | len_len; |
diff --git a/fs/ntfs/runlist.h b/fs/ntfs/runlist.h index cf5c1b44bea8..aa0ee6540e7c 100644 --- a/fs/ntfs/runlist.h +++ b/fs/ntfs/runlist.h | |||
@@ -84,11 +84,12 @@ extern runlist_element *ntfs_rl_find_vcn_nolock(runlist_element *rl, | |||
84 | const VCN vcn); | 84 | const VCN vcn); |
85 | 85 | ||
86 | extern int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol, | 86 | extern int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol, |
87 | const runlist_element *rl, const VCN start_vcn); | 87 | const runlist_element *rl, const VCN first_vcn, |
88 | const VCN last_vcn); | ||
88 | 89 | ||
89 | extern int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst, | 90 | extern int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst, |
90 | const int dst_len, const runlist_element *rl, | 91 | const int dst_len, const runlist_element *rl, |
91 | const VCN start_vcn, VCN *const stop_vcn); | 92 | const VCN first_vcn, const VCN last_vcn, VCN *const stop_vcn); |
92 | 93 | ||
93 | extern int ntfs_rl_truncate_nolock(const ntfs_volume *vol, | 94 | extern int ntfs_rl_truncate_nolock(const ntfs_volume *vol, |
94 | runlist *const runlist, const s64 new_length); | 95 | runlist *const runlist, const s64 new_length); |