NTFS: Change ntfs_map_runlist_nolock() to only decompress the mapping pairs
if the requested vcn is inside it. Otherwise we get into problems when we try to map an out of bounds vcn because we then try to map the already mapped runlist fragment which causes ntfs_mapping_pairs_decompress() to fail and return error. Update ntfs_attr_find_vcn_nolock() accordingly. Signed-off-by: Anton Altaparmakov <aia21@cantab.net>
This commit is contained in:
parent
fa3be92317
commit
4757d7dff6
2 changed files with 48 additions and 19 deletions
|
@ -139,6 +139,12 @@ ToDo/Notes:
|
|||
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.
|
||||
- Change ntfs_map_runlist_nolock() to only decompress the mapping pairs
|
||||
if the requested vcn is inside it. Otherwise we get into problems
|
||||
when we try to map an out of bounds vcn because we then try to map
|
||||
the already mapped runlist fragment which causes
|
||||
ntfs_mapping_pairs_decompress() to fail and return error. Update
|
||||
ntfs_attr_find_vcn_nolock() accordingly.
|
||||
|
||||
2.1.22 - Many bug and race fixes and error handling improvements.
|
||||
|
||||
|
|
|
@ -39,15 +39,19 @@
|
|||
*
|
||||
* Map the part of a runlist containing the @vcn of the ntfs inode @ni.
|
||||
*
|
||||
* Return 0 on success and -errno on error.
|
||||
* Return 0 on success and -errno on error. There is one special error code
|
||||
* which is not an error as such. This is -ENOENT. It means that @vcn is out
|
||||
* of bounds of the runlist.
|
||||
*
|
||||
* Locking: - The runlist must be locked for writing.
|
||||
* - This function modifies the runlist.
|
||||
*/
|
||||
int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn)
|
||||
{
|
||||
VCN end_vcn;
|
||||
ntfs_inode *base_ni;
|
||||
MFT_RECORD *mrec;
|
||||
MFT_RECORD *m;
|
||||
ATTR_RECORD *a;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
runlist_element *rl;
|
||||
int err = 0;
|
||||
|
@ -58,26 +62,43 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn)
|
|||
base_ni = ni;
|
||||
else
|
||||
base_ni = ni->ext.base_ntfs_ino;
|
||||
mrec = map_mft_record(base_ni);
|
||||
if (IS_ERR(mrec))
|
||||
return PTR_ERR(mrec);
|
||||
ctx = ntfs_attr_get_search_ctx(base_ni, mrec);
|
||||
m = map_mft_record(base_ni);
|
||||
if (IS_ERR(m))
|
||||
return PTR_ERR(m);
|
||||
ctx = ntfs_attr_get_search_ctx(base_ni, m);
|
||||
if (unlikely(!ctx)) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
|
||||
CASE_SENSITIVE, vcn, NULL, 0, ctx);
|
||||
if (likely(!err)) {
|
||||
rl = ntfs_mapping_pairs_decompress(ni->vol, ctx->attr,
|
||||
ni->runlist.rl);
|
||||
if (IS_ERR(rl))
|
||||
err = PTR_ERR(rl);
|
||||
else
|
||||
ni->runlist.rl = rl;
|
||||
if (unlikely(err)) {
|
||||
if (err == -ENOENT)
|
||||
err = -EIO;
|
||||
goto err_out;
|
||||
}
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
a = ctx->attr;
|
||||
/*
|
||||
* Only decompress the mapping pairs if @vcn is inside it. Otherwise
|
||||
* we get into problems when we try to map an out of bounds vcn because
|
||||
* we then try to map the already mapped runlist fragment and
|
||||
* ntfs_mapping_pairs_decompress() fails.
|
||||
*/
|
||||
end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn) + 1;
|
||||
if (unlikely(!a->data.non_resident.lowest_vcn && end_vcn <= 1))
|
||||
end_vcn = ni->allocated_size >> ni->vol->cluster_size_bits;
|
||||
if (unlikely(vcn >= end_vcn)) {
|
||||
err = -ENOENT;
|
||||
goto err_out;
|
||||
}
|
||||
rl = ntfs_mapping_pairs_decompress(ni->vol, a, ni->runlist.rl);
|
||||
if (IS_ERR(rl))
|
||||
err = PTR_ERR(rl);
|
||||
else
|
||||
ni->runlist.rl = rl;
|
||||
err_out:
|
||||
if (likely(ctx))
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
unmap_mft_record(base_ni);
|
||||
return err;
|
||||
}
|
||||
|
@ -89,7 +110,9 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn)
|
|||
*
|
||||
* Map the part of a runlist containing the @vcn of the ntfs inode @ni.
|
||||
*
|
||||
* Return 0 on success and -errno on error.
|
||||
* Return 0 on success and -errno on error. There is one special error code
|
||||
* which is not an error as such. This is -ENOENT. It means that @vcn is out
|
||||
* of bounds of the runlist.
|
||||
*
|
||||
* Locking: - The runlist must be unlocked on entry and is unlocked on return.
|
||||
* - This function takes the runlist lock for writing and modifies the
|
||||
|
@ -287,11 +310,11 @@ runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn,
|
|||
goto retry_remap;
|
||||
}
|
||||
/*
|
||||
* -EINVAL and -ENOENT coming from a failed mapping attempt are
|
||||
* equivalent to i/o errors for us as they should not happen in
|
||||
* our code paths.
|
||||
* -EINVAL coming from a failed mapping attempt is equivalent
|
||||
* to i/o error for us as it should not happen in our code
|
||||
* paths.
|
||||
*/
|
||||
if (err == -EINVAL || err == -ENOENT)
|
||||
if (err == -EINVAL)
|
||||
err = -EIO;
|
||||
} else if (!err)
|
||||
err = -EIO;
|
||||
|
|
Loading…
Reference in a new issue