diff options
Diffstat (limited to 'fs/ntfs/attrib.c')
-rw-r--r-- | fs/ntfs/attrib.c | 32 |
1 files changed, 31 insertions, 1 deletions
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 79dda3980684..98b5b96e8397 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c | |||
@@ -43,6 +43,9 @@ | |||
43 | * which is not an error as such. This is -ENOENT. It means that @vcn is out | 43 | * which is not an error as such. This is -ENOENT. It means that @vcn is out |
44 | * of bounds of the runlist. | 44 | * of bounds of the runlist. |
45 | * | 45 | * |
46 | * Note the runlist can be NULL after this function returns if @vcn is zero and | ||
47 | * the attribute has zero allocated size, i.e. there simply is no runlist. | ||
48 | * | ||
46 | * Locking: - The runlist must be locked for writing. | 49 | * Locking: - The runlist must be locked for writing. |
47 | * - This function modifies the runlist. | 50 | * - This function modifies the runlist. |
48 | */ | 51 | */ |
@@ -54,6 +57,7 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) | |||
54 | ATTR_RECORD *a; | 57 | ATTR_RECORD *a; |
55 | ntfs_attr_search_ctx *ctx; | 58 | ntfs_attr_search_ctx *ctx; |
56 | runlist_element *rl; | 59 | runlist_element *rl; |
60 | unsigned long flags; | ||
57 | int err = 0; | 61 | int err = 0; |
58 | 62 | ||
59 | ntfs_debug("Mapping runlist part containing vcn 0x%llx.", | 63 | ntfs_debug("Mapping runlist part containing vcn 0x%llx.", |
@@ -85,8 +89,11 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) | |||
85 | * ntfs_mapping_pairs_decompress() fails. | 89 | * ntfs_mapping_pairs_decompress() fails. |
86 | */ | 90 | */ |
87 | end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn) + 1; | 91 | end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn) + 1; |
88 | if (unlikely(!a->data.non_resident.lowest_vcn && end_vcn <= 1)) | 92 | if (unlikely(!a->data.non_resident.lowest_vcn && end_vcn <= 1)) { |
93 | read_lock_irqsave(&ni->size_lock, flags); | ||
89 | end_vcn = ni->allocated_size >> ni->vol->cluster_size_bits; | 94 | end_vcn = ni->allocated_size >> ni->vol->cluster_size_bits; |
95 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
96 | } | ||
90 | if (unlikely(vcn >= end_vcn)) { | 97 | if (unlikely(vcn >= end_vcn)) { |
91 | err = -ENOENT; | 98 | err = -ENOENT; |
92 | goto err_out; | 99 | goto err_out; |
@@ -165,6 +172,7 @@ LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn, | |||
165 | const BOOL write_locked) | 172 | const BOOL write_locked) |
166 | { | 173 | { |
167 | LCN lcn; | 174 | LCN lcn; |
175 | unsigned long flags; | ||
168 | BOOL is_retry = FALSE; | 176 | BOOL is_retry = FALSE; |
169 | 177 | ||
170 | ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.", | 178 | ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.", |
@@ -173,6 +181,14 @@ LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn, | |||
173 | BUG_ON(!ni); | 181 | BUG_ON(!ni); |
174 | BUG_ON(!NInoNonResident(ni)); | 182 | BUG_ON(!NInoNonResident(ni)); |
175 | BUG_ON(vcn < 0); | 183 | BUG_ON(vcn < 0); |
184 | if (!ni->runlist.rl) { | ||
185 | read_lock_irqsave(&ni->size_lock, flags); | ||
186 | if (!ni->allocated_size) { | ||
187 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
188 | return LCN_ENOENT; | ||
189 | } | ||
190 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
191 | } | ||
176 | retry_remap: | 192 | retry_remap: |
177 | /* Convert vcn to lcn. If that fails map the runlist and retry once. */ | 193 | /* Convert vcn to lcn. If that fails map the runlist and retry once. */ |
178 | lcn = ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn); | 194 | lcn = ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn); |
@@ -255,6 +271,7 @@ retry_remap: | |||
255 | runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, | 271 | runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, |
256 | const BOOL write_locked) | 272 | const BOOL write_locked) |
257 | { | 273 | { |
274 | unsigned long flags; | ||
258 | runlist_element *rl; | 275 | runlist_element *rl; |
259 | int err = 0; | 276 | int err = 0; |
260 | BOOL is_retry = FALSE; | 277 | BOOL is_retry = FALSE; |
@@ -265,6 +282,14 @@ runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, | |||
265 | BUG_ON(!ni); | 282 | BUG_ON(!ni); |
266 | BUG_ON(!NInoNonResident(ni)); | 283 | BUG_ON(!NInoNonResident(ni)); |
267 | BUG_ON(vcn < 0); | 284 | BUG_ON(vcn < 0); |
285 | if (!ni->runlist.rl) { | ||
286 | read_lock_irqsave(&ni->size_lock, flags); | ||
287 | if (!ni->allocated_size) { | ||
288 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
289 | return ERR_PTR(-ENOENT); | ||
290 | } | ||
291 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
292 | } | ||
268 | retry_remap: | 293 | retry_remap: |
269 | rl = ni->runlist.rl; | 294 | rl = ni->runlist.rl; |
270 | if (likely(rl && vcn >= rl[0].vcn)) { | 295 | if (likely(rl && vcn >= rl[0].vcn)) { |
@@ -528,6 +553,11 @@ int load_attribute_list(ntfs_volume *vol, runlist *runlist, u8 *al_start, | |||
528 | block_size_bits = sb->s_blocksize_bits; | 553 | block_size_bits = sb->s_blocksize_bits; |
529 | down_read(&runlist->lock); | 554 | down_read(&runlist->lock); |
530 | rl = runlist->rl; | 555 | rl = runlist->rl; |
556 | if (!rl) { | ||
557 | ntfs_error(sb, "Cannot read attribute list since runlist is " | ||
558 | "missing."); | ||
559 | goto err_out; | ||
560 | } | ||
531 | /* Read all clusters specified by the runlist one run at a time. */ | 561 | /* Read all clusters specified by the runlist one run at a time. */ |
532 | while (rl->length) { | 562 | while (rl->length) { |
533 | lcn = ntfs_rl_vcn_to_lcn(rl, rl->vcn); | 563 | lcn = ntfs_rl_vcn_to_lcn(rl, rl->vcn); |