diff options
Diffstat (limited to 'fs/ntfs/attrib.c')
-rw-r--r-- | fs/ntfs/attrib.c | 61 |
1 files changed, 42 insertions, 19 deletions
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index c6b2bb64d651..543d47fa5fc9 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c | |||
@@ -39,15 +39,19 @@ | |||
39 | * | 39 | * |
40 | * Map the part of a runlist containing the @vcn of the ntfs inode @ni. | 40 | * Map the part of a runlist containing the @vcn of the ntfs inode @ni. |
41 | * | 41 | * |
42 | * Return 0 on success and -errno on error. | 42 | * Return 0 on success and -errno on error. There is one special error code |
43 | * which is not an error as such. This is -ENOENT. It means that @vcn is out | ||
44 | * of bounds of the runlist. | ||
43 | * | 45 | * |
44 | * Locking: - The runlist must be locked for writing. | 46 | * Locking: - The runlist must be locked for writing. |
45 | * - This function modifies the runlist. | 47 | * - This function modifies the runlist. |
46 | */ | 48 | */ |
47 | int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) | 49 | int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) |
48 | { | 50 | { |
51 | VCN end_vcn; | ||
49 | ntfs_inode *base_ni; | 52 | ntfs_inode *base_ni; |
50 | MFT_RECORD *mrec; | 53 | MFT_RECORD *m; |
54 | ATTR_RECORD *a; | ||
51 | ntfs_attr_search_ctx *ctx; | 55 | ntfs_attr_search_ctx *ctx; |
52 | runlist_element *rl; | 56 | runlist_element *rl; |
53 | int err = 0; | 57 | int err = 0; |
@@ -58,26 +62,43 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) | |||
58 | base_ni = ni; | 62 | base_ni = ni; |
59 | else | 63 | else |
60 | base_ni = ni->ext.base_ntfs_ino; | 64 | base_ni = ni->ext.base_ntfs_ino; |
61 | mrec = map_mft_record(base_ni); | 65 | m = map_mft_record(base_ni); |
62 | if (IS_ERR(mrec)) | 66 | if (IS_ERR(m)) |
63 | return PTR_ERR(mrec); | 67 | return PTR_ERR(m); |
64 | ctx = ntfs_attr_get_search_ctx(base_ni, mrec); | 68 | ctx = ntfs_attr_get_search_ctx(base_ni, m); |
65 | if (unlikely(!ctx)) { | 69 | if (unlikely(!ctx)) { |
66 | err = -ENOMEM; | 70 | err = -ENOMEM; |
67 | goto err_out; | 71 | goto err_out; |
68 | } | 72 | } |
69 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, | 73 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, |
70 | CASE_SENSITIVE, vcn, NULL, 0, ctx); | 74 | CASE_SENSITIVE, vcn, NULL, 0, ctx); |
71 | if (likely(!err)) { | 75 | if (unlikely(err)) { |
72 | rl = ntfs_mapping_pairs_decompress(ni->vol, ctx->attr, | 76 | if (err == -ENOENT) |
73 | ni->runlist.rl); | 77 | err = -EIO; |
74 | if (IS_ERR(rl)) | 78 | goto err_out; |
75 | err = PTR_ERR(rl); | ||
76 | else | ||
77 | ni->runlist.rl = rl; | ||
78 | } | 79 | } |
79 | ntfs_attr_put_search_ctx(ctx); | 80 | a = ctx->attr; |
81 | /* | ||
82 | * Only decompress the mapping pairs if @vcn is inside it. Otherwise | ||
83 | * we get into problems when we try to map an out of bounds vcn because | ||
84 | * we then try to map the already mapped runlist fragment and | ||
85 | * ntfs_mapping_pairs_decompress() fails. | ||
86 | */ | ||
87 | end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn) + 1; | ||
88 | if (unlikely(!a->data.non_resident.lowest_vcn && end_vcn <= 1)) | ||
89 | end_vcn = ni->allocated_size >> ni->vol->cluster_size_bits; | ||
90 | if (unlikely(vcn >= end_vcn)) { | ||
91 | err = -ENOENT; | ||
92 | goto err_out; | ||
93 | } | ||
94 | rl = ntfs_mapping_pairs_decompress(ni->vol, a, ni->runlist.rl); | ||
95 | if (IS_ERR(rl)) | ||
96 | err = PTR_ERR(rl); | ||
97 | else | ||
98 | ni->runlist.rl = rl; | ||
80 | err_out: | 99 | err_out: |
100 | if (likely(ctx)) | ||
101 | ntfs_attr_put_search_ctx(ctx); | ||
81 | unmap_mft_record(base_ni); | 102 | unmap_mft_record(base_ni); |
82 | return err; | 103 | return err; |
83 | } | 104 | } |
@@ -89,7 +110,9 @@ err_out: | |||
89 | * | 110 | * |
90 | * Map the part of a runlist containing the @vcn of the ntfs inode @ni. | 111 | * Map the part of a runlist containing the @vcn of the ntfs inode @ni. |
91 | * | 112 | * |
92 | * Return 0 on success and -errno on error. | 113 | * Return 0 on success and -errno on error. There is one special error code |
114 | * which is not an error as such. This is -ENOENT. It means that @vcn is out | ||
115 | * of bounds of the runlist. | ||
93 | * | 116 | * |
94 | * Locking: - The runlist must be unlocked on entry and is unlocked on return. | 117 | * Locking: - The runlist must be unlocked on entry and is unlocked on return. |
95 | * - This function takes the runlist lock for writing and modifies the | 118 | * - This function takes the runlist lock for writing and modifies the |
@@ -287,11 +310,11 @@ retry_remap: | |||
287 | goto retry_remap; | 310 | goto retry_remap; |
288 | } | 311 | } |
289 | /* | 312 | /* |
290 | * -EINVAL and -ENOENT coming from a failed mapping attempt are | 313 | * -EINVAL coming from a failed mapping attempt is equivalent |
291 | * equivalent to i/o errors for us as they should not happen in | 314 | * to i/o error for us as it should not happen in our code |
292 | * our code paths. | 315 | * paths. |
293 | */ | 316 | */ |
294 | if (err == -EINVAL || err == -ENOENT) | 317 | if (err == -EINVAL) |
295 | err = -EIO; | 318 | err = -EIO; |
296 | } else if (!err) | 319 | } else if (!err) |
297 | err = -EIO; | 320 | err = -EIO; |