diff options
-rw-r--r-- | fs/ntfs/ChangeLog | 4 | ||||
-rw-r--r-- | fs/ntfs/inode.c | 172 | ||||
-rw-r--r-- | fs/ntfs/layout.h | 15 |
3 files changed, 94 insertions, 97 deletions
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index cf21e0571b68..cd348f0b90e5 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog | |||
@@ -84,6 +84,10 @@ ToDo/Notes: | |||
84 | - Make fs/ntfs/namei.c::ntfs_get_{parent,dentry} static and move the | 84 | - Make fs/ntfs/namei.c::ntfs_get_{parent,dentry} static and move the |
85 | definition of ntfs_export_ops from fs/ntfs/super.c to namei.c. Also, | 85 | definition of ntfs_export_ops from fs/ntfs/super.c to namei.c. Also, |
86 | declare ntfs_export_ops in fs/ntfs/ntfs.h. | 86 | declare ntfs_export_ops in fs/ntfs/ntfs.h. |
87 | - Correct sparse file handling. The compressed values need to be | ||
88 | checked and set in the ntfs inode as done for compressed files and | ||
89 | the compressed size needs to be used for vfs inode->i_blocks instead | ||
90 | of the allocated size, again, as done for compressed files. | ||
87 | 91 | ||
88 | 2.1.22 - Many bug and race fixes and error handling improvements. | 92 | 2.1.22 - Many bug and race fixes and error handling improvements. |
89 | 93 | ||
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 7ae647c640bb..f7bee8d014d9 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c | |||
@@ -1016,26 +1016,31 @@ skip_large_dir_stuff: | |||
1016 | /* Setup the state. */ | 1016 | /* Setup the state. */ |
1017 | if (a->non_resident) { | 1017 | if (a->non_resident) { |
1018 | NInoSetNonResident(ni); | 1018 | NInoSetNonResident(ni); |
1019 | if (a->flags & ATTR_COMPRESSION_MASK) { | 1019 | if (a->flags & (ATTR_COMPRESSION_MASK | |
1020 | NInoSetCompressed(ni); | 1020 | ATTR_IS_SPARSE)) { |
1021 | if (vol->cluster_size > 4096) { | 1021 | if (a->flags & ATTR_COMPRESSION_MASK) { |
1022 | ntfs_error(vi->i_sb, "Found " | 1022 | NInoSetCompressed(ni); |
1023 | "compressed data but " | 1023 | if (vol->cluster_size > 4096) { |
1024 | "compression is disabled due " | 1024 | ntfs_error(vi->i_sb, "Found " |
1025 | "to cluster size (%i) > 4kiB.", | 1025 | "compressed data but " |
1026 | vol->cluster_size); | 1026 | "compression is " |
1027 | goto unm_err_out; | 1027 | "disabled due to " |
1028 | } | 1028 | "cluster size (%i) > " |
1029 | if ((a->flags & ATTR_COMPRESSION_MASK) | 1029 | "4kiB.", |
1030 | != ATTR_IS_COMPRESSED) { | 1030 | vol->cluster_size); |
1031 | ntfs_error(vi->i_sb, "Found " | 1031 | goto unm_err_out; |
1032 | "unknown compression method or " | 1032 | } |
1033 | "corrupt file."); | 1033 | if ((a->flags & ATTR_COMPRESSION_MASK) |
1034 | goto unm_err_out; | 1034 | != ATTR_IS_COMPRESSED) { |
1035 | ntfs_error(vi->i_sb, "Found " | ||
1036 | "unknown compression " | ||
1037 | "method or corrupt " | ||
1038 | "file."); | ||
1039 | goto unm_err_out; | ||
1040 | } | ||
1035 | } | 1041 | } |
1036 | ni->itype.compressed.block_clusters = 1U << | 1042 | if (a->flags & ATTR_IS_SPARSE) |
1037 | a->data.non_resident. | 1043 | NInoSetSparse(ni); |
1038 | compression_unit; | ||
1039 | if (a->data.non_resident.compression_unit != | 1044 | if (a->data.non_resident.compression_unit != |
1040 | 4) { | 1045 | 4) { |
1041 | ntfs_error(vi->i_sb, "Found " | 1046 | ntfs_error(vi->i_sb, "Found " |
@@ -1047,12 +1052,19 @@ skip_large_dir_stuff: | |||
1047 | err = -EOPNOTSUPP; | 1052 | err = -EOPNOTSUPP; |
1048 | goto unm_err_out; | 1053 | goto unm_err_out; |
1049 | } | 1054 | } |
1055 | ni->itype.compressed.block_clusters = 1U << | ||
1056 | a->data.non_resident. | ||
1057 | compression_unit; | ||
1050 | ni->itype.compressed.block_size = 1U << ( | 1058 | ni->itype.compressed.block_size = 1U << ( |
1051 | a->data.non_resident. | 1059 | a->data.non_resident. |
1052 | compression_unit + | 1060 | compression_unit + |
1053 | vol->cluster_size_bits); | 1061 | vol->cluster_size_bits); |
1054 | ni->itype.compressed.block_size_bits = ffs( | 1062 | ni->itype.compressed.block_size_bits = ffs( |
1055 | ni->itype.compressed.block_size) - 1; | 1063 | ni->itype.compressed. |
1064 | block_size) - 1; | ||
1065 | ni->itype.compressed.size = sle64_to_cpu( | ||
1066 | a->data.non_resident. | ||
1067 | compressed_size); | ||
1056 | } | 1068 | } |
1057 | if (a->flags & ATTR_IS_ENCRYPTED) { | 1069 | if (a->flags & ATTR_IS_ENCRYPTED) { |
1058 | if (a->flags & ATTR_COMPRESSION_MASK) { | 1070 | if (a->flags & ATTR_COMPRESSION_MASK) { |
@@ -1062,27 +1074,19 @@ skip_large_dir_stuff: | |||
1062 | } | 1074 | } |
1063 | NInoSetEncrypted(ni); | 1075 | NInoSetEncrypted(ni); |
1064 | } | 1076 | } |
1065 | if (a->flags & ATTR_IS_SPARSE) | ||
1066 | NInoSetSparse(ni); | ||
1067 | if (a->data.non_resident.lowest_vcn) { | 1077 | if (a->data.non_resident.lowest_vcn) { |
1068 | ntfs_error(vi->i_sb, "First extent of $DATA " | 1078 | ntfs_error(vi->i_sb, "First extent of $DATA " |
1069 | "attribute has non zero " | 1079 | "attribute has non zero " |
1070 | "lowest_vcn."); | 1080 | "lowest_vcn."); |
1071 | goto unm_err_out; | 1081 | goto unm_err_out; |
1072 | } | 1082 | } |
1073 | /* Setup all the sizes. */ | ||
1074 | vi->i_size = sle64_to_cpu( | 1083 | vi->i_size = sle64_to_cpu( |
1075 | a->data.non_resident.data_size); | 1084 | a->data.non_resident.data_size); |
1076 | ni->initialized_size = sle64_to_cpu( | 1085 | ni->initialized_size = sle64_to_cpu( |
1077 | a->data.non_resident.initialized_size); | 1086 | a->data.non_resident.initialized_size); |
1078 | ni->allocated_size = sle64_to_cpu( | 1087 | ni->allocated_size = sle64_to_cpu( |
1079 | a->data.non_resident.allocated_size); | 1088 | a->data.non_resident.allocated_size); |
1080 | if (NInoCompressed(ni)) | ||
1081 | ni->itype.compressed.size = sle64_to_cpu( | ||
1082 | a->data.non_resident. | ||
1083 | compressed_size); | ||
1084 | } else { /* Resident attribute. */ | 1089 | } else { /* Resident attribute. */ |
1085 | /* Setup all the sizes. */ | ||
1086 | vi->i_size = ni->initialized_size = le32_to_cpu( | 1090 | vi->i_size = ni->initialized_size = le32_to_cpu( |
1087 | a->data.resident.value_length); | 1091 | a->data.resident.value_length); |
1088 | ni->allocated_size = le32_to_cpu(a->length) - | 1092 | ni->allocated_size = le32_to_cpu(a->length) - |
@@ -1120,11 +1124,10 @@ no_data_attr_special_case: | |||
1120 | * sizes of all non-resident attributes present to give us the Linux | 1124 | * sizes of all non-resident attributes present to give us the Linux |
1121 | * correct size that should go into i_blocks (after division by 512). | 1125 | * correct size that should go into i_blocks (after division by 512). |
1122 | */ | 1126 | */ |
1123 | if (S_ISDIR(vi->i_mode) || !NInoCompressed(ni)) | 1127 | if (S_ISREG(vi->i_mode) && (NInoCompressed(ni) || NInoSparse(ni))) |
1124 | vi->i_blocks = ni->allocated_size >> 9; | ||
1125 | else | ||
1126 | vi->i_blocks = ni->itype.compressed.size >> 9; | 1128 | vi->i_blocks = ni->itype.compressed.size >> 9; |
1127 | 1129 | else | |
1130 | vi->i_blocks = ni->allocated_size >> 9; | ||
1128 | ntfs_debug("Done."); | 1131 | ntfs_debug("Done."); |
1129 | return 0; | 1132 | return 0; |
1130 | 1133 | ||
@@ -1226,14 +1229,13 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) | |||
1226 | "linux-ntfs-dev@lists.sourceforge.net"); | 1229 | "linux-ntfs-dev@lists.sourceforge.net"); |
1227 | goto unm_err_out; | 1230 | goto unm_err_out; |
1228 | } | 1231 | } |
1229 | /* Resident attribute. Setup all the sizes. */ | ||
1230 | vi->i_size = ni->initialized_size = le32_to_cpu( | 1232 | vi->i_size = ni->initialized_size = le32_to_cpu( |
1231 | a->data.resident.value_length); | 1233 | a->data.resident.value_length); |
1232 | ni->allocated_size = le32_to_cpu(a->length) - | 1234 | ni->allocated_size = le32_to_cpu(a->length) - |
1233 | le16_to_cpu(a->data.resident.value_offset); | 1235 | le16_to_cpu(a->data.resident.value_offset); |
1234 | if (vi->i_size > ni->allocated_size) { | 1236 | if (vi->i_size > ni->allocated_size) { |
1235 | ntfs_error(vi->i_sb, "Resident data attribute is " | 1237 | ntfs_error(vi->i_sb, "Resident attribute is corrupt " |
1236 | "corrupt (size exceeds allocation)."); | 1238 | "(size exceeds allocation)."); |
1237 | goto unm_err_out; | 1239 | goto unm_err_out; |
1238 | } | 1240 | } |
1239 | } else { | 1241 | } else { |
@@ -1249,43 +1251,50 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) | |||
1249 | "the mapping pairs array."); | 1251 | "the mapping pairs array."); |
1250 | goto unm_err_out; | 1252 | goto unm_err_out; |
1251 | } | 1253 | } |
1252 | if (a->flags & ATTR_COMPRESSION_MASK) { | 1254 | if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) { |
1255 | if (a->flags & ATTR_COMPRESSION_MASK) { | ||
1256 | NInoSetCompressed(ni); | ||
1257 | if ((ni->type != AT_DATA) || (ni->type == | ||
1258 | AT_DATA && ni->name_len)) { | ||
1259 | ntfs_error(vi->i_sb, "Found compressed " | ||
1260 | "non-data or named " | ||
1261 | "data attribute. " | ||
1262 | "Please report you " | ||
1263 | "saw this message to " | ||
1264 | "linux-ntfs-dev@lists." | ||
1265 | "sourceforge.net"); | ||
1266 | goto unm_err_out; | ||
1267 | } | ||
1268 | if (vol->cluster_size > 4096) { | ||
1269 | ntfs_error(vi->i_sb, "Found compressed " | ||
1270 | "attribute but " | ||
1271 | "compression is " | ||
1272 | "disabled due to " | ||
1273 | "cluster size (%i) > " | ||
1274 | "4kiB.", | ||
1275 | vol->cluster_size); | ||
1276 | goto unm_err_out; | ||
1277 | } | ||
1278 | if ((a->flags & ATTR_COMPRESSION_MASK) != | ||
1279 | ATTR_IS_COMPRESSED) { | ||
1280 | ntfs_error(vi->i_sb, "Found unknown " | ||
1281 | "compression method."); | ||
1282 | goto unm_err_out; | ||
1283 | } | ||
1284 | } | ||
1253 | if (NInoMstProtected(ni)) { | 1285 | if (NInoMstProtected(ni)) { |
1254 | ntfs_error(vi->i_sb, "Found mst protected " | 1286 | ntfs_error(vi->i_sb, "Found mst protected " |
1255 | "attribute but the attribute " | 1287 | "attribute but the attribute " |
1256 | "is compressed. Please report " | 1288 | "is %s. Please report you " |
1257 | "you saw this message to " | 1289 | "saw this message to " |
1258 | "linux-ntfs-dev@lists." | ||
1259 | "sourceforge.net"); | ||
1260 | goto unm_err_out; | ||
1261 | } | ||
1262 | NInoSetCompressed(ni); | ||
1263 | if ((ni->type != AT_DATA) || (ni->type == AT_DATA && | ||
1264 | ni->name_len)) { | ||
1265 | ntfs_error(vi->i_sb, "Found compressed " | ||
1266 | "non-data or named data " | ||
1267 | "attribute. Please report " | ||
1268 | "you saw this message to " | ||
1269 | "linux-ntfs-dev@lists." | 1290 | "linux-ntfs-dev@lists." |
1270 | "sourceforge.net"); | 1291 | "sourceforge.net", |
1271 | goto unm_err_out; | 1292 | NInoCompressed(ni) ? |
1272 | } | 1293 | "compressed" : "sparse"); |
1273 | if (vol->cluster_size > 4096) { | ||
1274 | ntfs_error(vi->i_sb, "Found compressed " | ||
1275 | "attribute but compression is " | ||
1276 | "disabled due to cluster size " | ||
1277 | "(%i) > 4kiB.", | ||
1278 | vol->cluster_size); | ||
1279 | goto unm_err_out; | ||
1280 | } | ||
1281 | if ((a->flags & ATTR_COMPRESSION_MASK) != | ||
1282 | ATTR_IS_COMPRESSED) { | ||
1283 | ntfs_error(vi->i_sb, "Found unknown " | ||
1284 | "compression method."); | ||
1285 | goto unm_err_out; | 1294 | goto unm_err_out; |
1286 | } | 1295 | } |
1287 | ni->itype.compressed.block_clusters = 1U << | 1296 | if (a->flags & ATTR_IS_SPARSE) |
1288 | a->data.non_resident.compression_unit; | 1297 | NInoSetSparse(ni); |
1289 | if (a->data.non_resident.compression_unit != 4) { | 1298 | if (a->data.non_resident.compression_unit != 4) { |
1290 | ntfs_error(vi->i_sb, "Found nonstandard " | 1299 | ntfs_error(vi->i_sb, "Found nonstandard " |
1291 | "compression unit (%u instead " | 1300 | "compression unit (%u instead " |
@@ -1295,11 +1304,15 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) | |||
1295 | err = -EOPNOTSUPP; | 1304 | err = -EOPNOTSUPP; |
1296 | goto unm_err_out; | 1305 | goto unm_err_out; |
1297 | } | 1306 | } |
1307 | ni->itype.compressed.block_clusters = 1U << | ||
1308 | a->data.non_resident.compression_unit; | ||
1298 | ni->itype.compressed.block_size = 1U << ( | 1309 | ni->itype.compressed.block_size = 1U << ( |
1299 | a->data.non_resident.compression_unit + | 1310 | a->data.non_resident.compression_unit + |
1300 | vol->cluster_size_bits); | 1311 | vol->cluster_size_bits); |
1301 | ni->itype.compressed.block_size_bits = ffs( | 1312 | ni->itype.compressed.block_size_bits = ffs( |
1302 | ni->itype.compressed.block_size) - 1; | 1313 | ni->itype.compressed.block_size) - 1; |
1314 | ni->itype.compressed.size = sle64_to_cpu( | ||
1315 | a->data.non_resident.compressed_size); | ||
1303 | } | 1316 | } |
1304 | if (a->flags & ATTR_IS_ENCRYPTED) { | 1317 | if (a->flags & ATTR_IS_ENCRYPTED) { |
1305 | if (a->flags & ATTR_COMPRESSION_MASK) { | 1318 | if (a->flags & ATTR_COMPRESSION_MASK) { |
@@ -1318,34 +1331,17 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) | |||
1318 | } | 1331 | } |
1319 | NInoSetEncrypted(ni); | 1332 | NInoSetEncrypted(ni); |
1320 | } | 1333 | } |
1321 | if (a->flags & ATTR_IS_SPARSE) { | ||
1322 | if (NInoMstProtected(ni)) { | ||
1323 | ntfs_error(vi->i_sb, "Found mst protected " | ||
1324 | "attribute but the attribute " | ||
1325 | "is sparse. Please report " | ||
1326 | "you saw this message to " | ||
1327 | "linux-ntfs-dev@lists." | ||
1328 | "sourceforge.net"); | ||
1329 | goto unm_err_out; | ||
1330 | } | ||
1331 | NInoSetSparse(ni); | ||
1332 | } | ||
1333 | if (a->data.non_resident.lowest_vcn) { | 1334 | if (a->data.non_resident.lowest_vcn) { |
1334 | ntfs_error(vi->i_sb, "First extent of attribute has " | 1335 | ntfs_error(vi->i_sb, "First extent of attribute has " |
1335 | "non-zero lowest_vcn."); | 1336 | "non-zero lowest_vcn."); |
1336 | goto unm_err_out; | 1337 | goto unm_err_out; |
1337 | } | 1338 | } |
1338 | /* Setup all the sizes. */ | ||
1339 | vi->i_size = sle64_to_cpu(a->data.non_resident.data_size); | 1339 | vi->i_size = sle64_to_cpu(a->data.non_resident.data_size); |
1340 | ni->initialized_size = sle64_to_cpu( | 1340 | ni->initialized_size = sle64_to_cpu( |
1341 | a->data.non_resident.initialized_size); | 1341 | a->data.non_resident.initialized_size); |
1342 | ni->allocated_size = sle64_to_cpu( | 1342 | ni->allocated_size = sle64_to_cpu( |
1343 | a->data.non_resident.allocated_size); | 1343 | a->data.non_resident.allocated_size); |
1344 | if (NInoCompressed(ni)) | ||
1345 | ni->itype.compressed.size = sle64_to_cpu( | ||
1346 | a->data.non_resident.compressed_size); | ||
1347 | } | 1344 | } |
1348 | |||
1349 | /* Setup the operations for this attribute inode. */ | 1345 | /* Setup the operations for this attribute inode. */ |
1350 | vi->i_op = NULL; | 1346 | vi->i_op = NULL; |
1351 | vi->i_fop = NULL; | 1347 | vi->i_fop = NULL; |
@@ -1353,12 +1349,10 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) | |||
1353 | vi->i_mapping->a_ops = &ntfs_mst_aops; | 1349 | vi->i_mapping->a_ops = &ntfs_mst_aops; |
1354 | else | 1350 | else |
1355 | vi->i_mapping->a_ops = &ntfs_aops; | 1351 | vi->i_mapping->a_ops = &ntfs_aops; |
1356 | 1352 | if (NInoCompressed(ni) || NInoSparse(ni)) | |
1357 | if (!NInoCompressed(ni)) | ||
1358 | vi->i_blocks = ni->allocated_size >> 9; | ||
1359 | else | ||
1360 | vi->i_blocks = ni->itype.compressed.size >> 9; | 1353 | vi->i_blocks = ni->itype.compressed.size >> 9; |
1361 | 1354 | else | |
1355 | vi->i_blocks = ni->allocated_size >> 9; | ||
1362 | /* | 1356 | /* |
1363 | * Make sure the base inode doesn't go away and attach it to the | 1357 | * Make sure the base inode doesn't go away and attach it to the |
1364 | * attribute inode. | 1358 | * attribute inode. |
@@ -1643,7 +1637,6 @@ skip_large_index_stuff: | |||
1643 | vi->i_fop = NULL; | 1637 | vi->i_fop = NULL; |
1644 | vi->i_mapping->a_ops = &ntfs_mst_aops; | 1638 | vi->i_mapping->a_ops = &ntfs_mst_aops; |
1645 | vi->i_blocks = ni->allocated_size >> 9; | 1639 | vi->i_blocks = ni->allocated_size >> 9; |
1646 | |||
1647 | /* | 1640 | /* |
1648 | * Make sure the base inode doesn't go away and attach it to the | 1641 | * Make sure the base inode doesn't go away and attach it to the |
1649 | * index inode. | 1642 | * index inode. |
@@ -1728,7 +1721,6 @@ int ntfs_read_inode_mount(struct inode *vi) | |||
1728 | ni->type = AT_DATA; | 1721 | ni->type = AT_DATA; |
1729 | ni->name = NULL; | 1722 | ni->name = NULL; |
1730 | ni->name_len = 0; | 1723 | ni->name_len = 0; |
1731 | |||
1732 | /* | 1724 | /* |
1733 | * This sets up our little cheat allowing us to reuse the async read io | 1725 | * This sets up our little cheat allowing us to reuse the async read io |
1734 | * completion handler for directories. | 1726 | * completion handler for directories. |
diff --git a/fs/ntfs/layout.h b/fs/ntfs/layout.h index 7cb8806d4559..8d1f1326612f 100644 --- a/fs/ntfs/layout.h +++ b/fs/ntfs/layout.h | |||
@@ -749,10 +749,11 @@ typedef struct { | |||
749 | record header aligned to 8-byte boundary. */ | 749 | record header aligned to 8-byte boundary. */ |
750 | /* 34*/ u8 compression_unit; /* The compression unit expressed | 750 | /* 34*/ u8 compression_unit; /* The compression unit expressed |
751 | as the log to the base 2 of the number of | 751 | as the log to the base 2 of the number of |
752 | clusters in a compression unit. 0 means not | 752 | clusters in a compression unit. 0 means not |
753 | compressed. (This effectively limits the | 753 | compressed. (This effectively limits the |
754 | compression unit size to be a power of two | 754 | compression unit size to be a power of two |
755 | clusters.) WinNT4 only uses a value of 4. */ | 755 | clusters.) WinNT4 only uses a value of 4. |
756 | Sparse files also have this set to 4. */ | ||
756 | /* 35*/ u8 reserved[5]; /* Align to 8-byte boundary. */ | 757 | /* 35*/ u8 reserved[5]; /* Align to 8-byte boundary. */ |
757 | /* The sizes below are only used when lowest_vcn is zero, as otherwise it would | 758 | /* The sizes below are only used when lowest_vcn is zero, as otherwise it would |
758 | be difficult to keep them up-to-date.*/ | 759 | be difficult to keep them up-to-date.*/ |
@@ -772,10 +773,10 @@ typedef struct { | |||
772 | data_size. */ | 773 | data_size. */ |
773 | /* sizeof(uncompressed attr) = 64*/ | 774 | /* sizeof(uncompressed attr) = 64*/ |
774 | /* 64*/ sle64 compressed_size; /* Byte size of the attribute | 775 | /* 64*/ sle64 compressed_size; /* Byte size of the attribute |
775 | value after compression. Only present when | 776 | value after compression. Only present when |
776 | compressed. Always is a multiple of the | 777 | compressed or sparse. Always is a multiple of |
777 | cluster size. Represents the actual amount of | 778 | the cluster size. Represents the actual amount |
778 | disk space being used on the disk. */ | 779 | of disk space being used on the disk. */ |
779 | /* sizeof(compressed attr) = 72*/ | 780 | /* sizeof(compressed attr) = 72*/ |
780 | } __attribute__ ((__packed__)) non_resident; | 781 | } __attribute__ ((__packed__)) non_resident; |
781 | } __attribute__ ((__packed__)) data; | 782 | } __attribute__ ((__packed__)) data; |