diff options
| author | Anton Altaparmakov <aia21@cantab.net> | 2005-06-25 12:15:36 -0400 |
|---|---|---|
| committer | Anton Altaparmakov <aia21@cantab.net> | 2005-06-25 12:15:36 -0400 |
| commit | fa3be92317c4ae34edcf5274e8bbeff181e20b7a (patch) | |
| tree | 84ae4ace6c891aa95b804950283e1f8f3e46c730 | |
| parent | 1d58b27b8d77ecb816cfa8f846b78c845675eb89 (diff) | |
NTFS: Add an extra parameter @last_vcn to ntfs_get_size_for_mapping_pairs()
and ntfs_mapping_pairs_build() to allow the runlist encoding to be
partial which is desirable when filling holes in sparse attributes.
Update all callers.
Signed-off-by: Anton Altaparmakov <aia21@cantab.net>
| -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); |
