O(1) mapping pairs update for normal files
parent
b99d331f78
commit
48c336fd6a
133
libntfs/attrib.c
133
libntfs/attrib.c
|
@ -1392,7 +1392,7 @@ done:
|
|||
ntfs_attr_put_search_ctx(ctx);
|
||||
/* Update mapping pairs if needed. */
|
||||
if (need_to.update_mapping_pairs)
|
||||
ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/);
|
||||
ntfs_attr_update_mapping_pairs(na, update_from);
|
||||
/* Finally, return the number of bytes written. */
|
||||
return total;
|
||||
rl_err_out:
|
||||
|
@ -1450,7 +1450,7 @@ err_out:
|
|||
ntfs_attr_put_search_ctx(ctx);
|
||||
/* Update mapping pairs if needed. */
|
||||
if (need_to.update_mapping_pairs)
|
||||
ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/);
|
||||
ntfs_attr_update_mapping_pairs(na, update_from);
|
||||
/* Restore original data_size if needed. */
|
||||
if (need_to.undo_data_size && ntfs_attr_truncate(na, old_data_size))
|
||||
ntfs_log_trace("Failed to restore data_size.\n");
|
||||
|
@ -4186,11 +4186,18 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx)
|
|||
* call to this function. Vice-versa @na->compressed_size will be calculated and
|
||||
* set to correct value during this function.
|
||||
*
|
||||
* FIXME: This function does not update sparse bit and compressed size correctly
|
||||
* if called with @from_vcn != 0.
|
||||
* New runlist should be fully formed starting @from_vcn. Runs before @from_vcn
|
||||
* can be mapped or not, but on-disk structures should not be modified before
|
||||
* call to this function so they can be mapped if necessary.
|
||||
*
|
||||
* FIXME: Make it O(1) for sparse files too, not only for normal.
|
||||
*
|
||||
* FIXME: Rewrite without using NTFS_VCN_DELETE_MARK define.
|
||||
*
|
||||
* NOTE: Be careful in the future with updating bits on compressed files (at
|
||||
* present assumed that on-disk flag is already set/cleared before call to
|
||||
* this function).
|
||||
*
|
||||
* On success return 0 and on error return -1 with errno set to the error code.
|
||||
* The following error codes are defined:
|
||||
* EINVAL - Invalid arguments passed.
|
||||
|
@ -4209,7 +4216,7 @@ int ntfs_attr_update_mapping_pairs(ntfs_attr *na, VCN from_vcn)
|
|||
BOOL finished_build;
|
||||
|
||||
retry:
|
||||
if (!na || !na->rl || from_vcn) {
|
||||
if (!na || !na->rl) {
|
||||
ntfs_log_trace("Invalid parameters passed.\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
|
@ -4221,8 +4228,9 @@ retry:
|
|||
return -1;
|
||||
}
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long
|
||||
long)na->ni->mft_no, na->type);
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, from vcn 0x%lld."
|
||||
"\n", (unsigned long long)na->ni->mft_no, na->type,
|
||||
from_vcn);
|
||||
|
||||
if (na->ni->nr_extents == -1)
|
||||
base_ni = na->ni->base_ni;
|
||||
|
@ -4239,7 +4247,8 @@ retry:
|
|||
stop_vcn = 0;
|
||||
finished_build = FALSE;
|
||||
while (!ntfs_attr_lookup(na->type, na->name, na->name_len,
|
||||
CASE_SENSITIVE, from_vcn, NULL, 0, ctx)) {
|
||||
CASE_SENSITIVE, ctx->is_first ? 0 : from_vcn,
|
||||
NULL, 0, ctx)) {
|
||||
a = ctx->attr;
|
||||
m = ctx->mrec;
|
||||
/*
|
||||
|
@ -4248,7 +4257,7 @@ retry:
|
|||
* contain @from_vcn. Also we do not need @from_vcn anymore,
|
||||
* set it to 0 to make ntfs_attr_lookup enumerate attributes.
|
||||
*/
|
||||
if (from_vcn) {
|
||||
if (from_vcn && a->lowest_vcn) {
|
||||
LCN first_lcn;
|
||||
|
||||
stop_vcn = sle64_to_cpu(a->lowest_vcn);
|
||||
|
@ -4256,7 +4265,7 @@ retry:
|
|||
/*
|
||||
* Check whether the first run we need to update is
|
||||
* the last run in runlist, if so, then deallocate
|
||||
* all attrubute extents starting this one.
|
||||
* all attribute extents starting this one.
|
||||
*/
|
||||
first_lcn = ntfs_rl_vcn_to_lcn(na->rl, stop_vcn);
|
||||
if (first_lcn == LCN_EINVAL) {
|
||||
|
@ -4307,14 +4316,43 @@ retry:
|
|||
|
||||
/* Update allocated size. */
|
||||
a->allocated_size = cpu_to_sle64(na->allocated_size);
|
||||
/* Update sparse bit. */
|
||||
/*
|
||||
* Check whether part of runlist we are updating is
|
||||
* sparse.
|
||||
*/
|
||||
sparse = ntfs_rl_sparse(na->rl);
|
||||
if (sparse == -1) {
|
||||
ntfs_log_trace("Bad runlist.\n");
|
||||
err = EIO;
|
||||
err = errno;
|
||||
goto put_err_out;
|
||||
}
|
||||
/* Attribute become sparse. */
|
||||
/*
|
||||
* If new part or on-disk attribute is not sparse, then
|
||||
* we should fully map runlist to make final decision.
|
||||
*/
|
||||
if (sparse || (a->flags & ATTR_IS_SPARSE)) {
|
||||
if (from_vcn && ntfs_attr_map_runlist_range(na,
|
||||
0, from_vcn - 1)) {
|
||||
ntfs_log_trace("Failed to map runlist "
|
||||
"before @from_vcn.\n");
|
||||
err = errno;
|
||||
goto put_err_out;
|
||||
}
|
||||
/*
|
||||
* Reconsider whether whole runlist is sparse
|
||||
* if new part is not.
|
||||
*/
|
||||
if (!sparse) {
|
||||
sparse = ntfs_rl_sparse(na->rl);
|
||||
if (sparse == -1) {
|
||||
ntfs_log_trace("Bad "
|
||||
"runlist.\n");
|
||||
err = errno;
|
||||
goto put_err_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Attribute becomes sparse/compressed. */
|
||||
if (sparse && !(a->flags & (ATTR_IS_SPARSE |
|
||||
ATTR_IS_COMPRESSED))) {
|
||||
/*
|
||||
|
@ -4369,8 +4407,13 @@ retry:
|
|||
a->mapping_pairs_offset =
|
||||
cpu_to_le16(le16_to_cpu(
|
||||
a->mapping_pairs_offset) + 8);
|
||||
/*
|
||||
* We should update all mapping pairs, because
|
||||
* we shifted their starting position.
|
||||
*/
|
||||
from_vcn = 0;
|
||||
}
|
||||
/* Attribute no longer sparse. */
|
||||
/* Attribute becomes normal. */
|
||||
if (!sparse && (a->flags & ATTR_IS_SPARSE) &&
|
||||
!(a->flags & ATTR_IS_COMPRESSED)) {
|
||||
NAttrClearSparse(na);
|
||||
|
@ -4384,9 +4427,14 @@ retry:
|
|||
a->mapping_pairs_offset =
|
||||
cpu_to_le16(le16_to_cpu(
|
||||
a->mapping_pairs_offset) - 8);
|
||||
/*
|
||||
* We should update all mapping pairs, because
|
||||
* we shifted their starting position.
|
||||
*/
|
||||
from_vcn = 0;
|
||||
}
|
||||
/* Update compressed size if required. */
|
||||
if (sparse) {
|
||||
if (sparse || (a->flags & ATTR_IS_COMPRESSED)) {
|
||||
s64 new_compr_size;
|
||||
|
||||
new_compr_size = ntfs_rl_get_compressed_size(
|
||||
|
@ -4415,7 +4463,21 @@ retry:
|
|||
na->allocated_size;
|
||||
NInoFileNameSetDirty(na->ni);
|
||||
}
|
||||
|
||||
/*
|
||||
* We do want to do anything for the first extent in
|
||||
* case we are updating mapping pairs not from the
|
||||
* begging.
|
||||
*/
|
||||
if (!a->highest_vcn || from_vcn <=
|
||||
sle64_to_cpu(a->highest_vcn) + 1)
|
||||
from_vcn = 0;
|
||||
else {
|
||||
if (from_vcn)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the size for the rest of mapping pairs array. */
|
||||
mp_size = ntfs_get_size_for_mapping_pairs(na->ni->vol, na->rl,
|
||||
stop_vcn);
|
||||
|
@ -4531,6 +4593,13 @@ retry:
|
|||
ntfs_log_trace("Attribute lookup failed.\n");
|
||||
goto put_err_out;
|
||||
}
|
||||
/* Sanity check. */
|
||||
if (from_vcn) {
|
||||
err = ENOMSG;
|
||||
ntfs_log_error("Library BUG! @from_vcn is nonzero, please "
|
||||
"report to %s.\n", NTFS_DEV_LIST);
|
||||
goto put_err_out;
|
||||
}
|
||||
|
||||
/* Deallocate not used attribute extents and return with success. */
|
||||
if (finished_build) {
|
||||
|
@ -4557,6 +4626,7 @@ retry:
|
|||
}
|
||||
ntfs_log_trace("Deallocate done.\n");
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
ntfs_log_trace("Done!");
|
||||
return 0;
|
||||
}
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
|
@ -4625,6 +4695,7 @@ retry:
|
|||
if (!err)
|
||||
break;
|
||||
}
|
||||
ntfs_log_trace("Done!\n");
|
||||
return 0;
|
||||
put_err_out:
|
||||
if (ctx)
|
||||
|
@ -4712,7 +4783,7 @@ static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize)
|
|||
/* Prepare to mapping pairs update. */
|
||||
na->allocated_size = first_free_vcn << vol->cluster_size_bits;
|
||||
/* Write mapping pairs for new runlist. */
|
||||
if (ntfs_attr_update_mapping_pairs(na, 0 /*first_free_vcn*/)) {
|
||||
if (ntfs_attr_update_mapping_pairs(na, first_free_vcn)) {
|
||||
ntfs_log_trace("Eeek! Mapping pairs update failed. "
|
||||
"Leaving inconsistent metadata. "
|
||||
"Run chkdsk.\n");
|
||||
|
@ -4788,7 +4859,6 @@ put_err_out:
|
|||
static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize,
|
||||
BOOL sparse)
|
||||
{
|
||||
LCN lcn_seek_from;
|
||||
VCN first_free_vcn;
|
||||
ntfs_volume *vol;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
|
@ -4826,9 +4896,10 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize,
|
|||
* clusters if there is a change.
|
||||
*/
|
||||
if ((na->allocated_size >> vol->cluster_size_bits) < first_free_vcn) {
|
||||
if (ntfs_attr_map_whole_runlist(na)) {
|
||||
ntfs_log_trace("Eeek! ntfs_attr_map_whole_runlist "
|
||||
"failed.\n");
|
||||
/* Map required part of runlist. */
|
||||
if (ntfs_attr_map_runlist(na, na->allocated_size >>
|
||||
vol->cluster_size_bits)) {
|
||||
ntfs_log_error("Failed to map runlist.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -4857,6 +4928,8 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize,
|
|||
* attribute let the cluster allocator choose the
|
||||
* starting LCN.
|
||||
*/
|
||||
LCN lcn_seek_from;
|
||||
|
||||
lcn_seek_from = -1;
|
||||
if (na->rl->length) {
|
||||
/* Seek to the last run list element. */
|
||||
|
@ -4891,7 +4964,7 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize,
|
|||
if (!rln) {
|
||||
/* Failed, free just allocated clusters. */
|
||||
err = errno;
|
||||
ntfs_log_trace("Eeek! Run list merge failed.\n");
|
||||
ntfs_log_trace("Run list merge failed.\n");
|
||||
ntfs_cluster_free_from_rl(vol, rl);
|
||||
free(rl);
|
||||
errno = err;
|
||||
|
@ -4902,10 +4975,10 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize,
|
|||
/* Prepare to mapping pairs update. */
|
||||
na->allocated_size = first_free_vcn << vol->cluster_size_bits;
|
||||
/* Write mapping pairs for new runlist. */
|
||||
if (ntfs_attr_update_mapping_pairs(na, 0 /*na->allocated_size >>
|
||||
vol->cluster_size_bits*/)) {
|
||||
if (ntfs_attr_update_mapping_pairs(na, org_alloc_size >>
|
||||
vol->cluster_size_bits)) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Eeek! Mapping pairs update failed.\n");
|
||||
ntfs_log_trace("Mapping pairs update failed.\n");
|
||||
goto rollback;
|
||||
}
|
||||
}
|
||||
|
@ -4965,10 +5038,10 @@ rollback:
|
|||
ntfs_log_trace("Couldn't truncate runlist. Rollback failed.\n");
|
||||
} else {
|
||||
/* Prepare to mapping pairs update. */
|
||||
na->allocated_size = org_alloc_size << vol->cluster_size_bits;
|
||||
na->allocated_size = org_alloc_size;
|
||||
/* Restore mapping pairs. */
|
||||
if (ntfs_attr_update_mapping_pairs(na, 0 /*na->allocated_size >>
|
||||
vol->cluster_size_bits*/)) {
|
||||
if (ntfs_attr_update_mapping_pairs(na, na->allocated_size >>
|
||||
vol->cluster_size_bits)) {
|
||||
ntfs_log_trace("Failed to restore old mapping pairs. "
|
||||
"Rollback failed.\n");
|
||||
}
|
||||
|
@ -5028,6 +5101,7 @@ int __ntfs_attr_truncate(ntfs_attr *na, const s64 newsize, BOOL sparse)
|
|||
*/
|
||||
if (NAttrEncrypted(na)) {
|
||||
errno = EACCES;
|
||||
ntfs_log_trace("Failed (encrypted).\n");
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
|
@ -5035,6 +5109,7 @@ int __ntfs_attr_truncate(ntfs_attr *na, const s64 newsize, BOOL sparse)
|
|||
*/
|
||||
if (NAttrCompressed(na)) {
|
||||
errno = EOPNOTSUPP;
|
||||
ntfs_log_trace("Failed (compressed).\n");
|
||||
return -1;
|
||||
}
|
||||
if (NAttrNonResident(na)) {
|
||||
|
@ -5049,6 +5124,10 @@ int __ntfs_attr_truncate(ntfs_attr *na, const s64 newsize, BOOL sparse)
|
|||
if (na->type == AT_DATA || na->type == AT_INDEX_ROOT ||
|
||||
na->type == AT_INDEX_ALLOCATION)
|
||||
ntfs_inode_update_time(na->ni);
|
||||
if (!ret)
|
||||
ntfs_log_trace("Done!\n");
|
||||
else
|
||||
ntfs_log_trace("Failed.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -436,7 +436,7 @@ static runlist_element *ntfs_rl_split(runlist_element *dst,
|
|||
int dsize, runlist_element *src, int ssize, int loc)
|
||||
{
|
||||
if (!dst || !src) {
|
||||
ntfs_log_debug("Eeek. ntfs_rl_split() invoked with NULL pointer!\n");
|
||||
ntfs_log_trace("Invoked with NULL pointer!\n");
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1630,6 +1630,10 @@ int ntfs_rl_truncate(runlist **arl, const VCN start_vcn)
|
|||
* ntfs_rl_sparse - check whether runlist have sparse regions or not.
|
||||
* @rl: runlist to check
|
||||
*
|
||||
* This function just skips not mapped regions assuming they are not sparse,
|
||||
* so you need to ensure that runlist is fully mapped if you want perform full
|
||||
* check.
|
||||
*
|
||||
* Return 1 if have, 0 if not, -1 on error with errno set to the error code.
|
||||
*/
|
||||
int ntfs_rl_sparse(runlist *rl)
|
||||
|
@ -1642,15 +1646,18 @@ int ntfs_rl_sparse(runlist *rl)
|
|||
return -1;
|
||||
}
|
||||
|
||||
for (rlc = rl; rlc->length; rlc++)
|
||||
for (rlc = rl; rlc->length; rlc++) {
|
||||
if (rlc->lcn < 0) {
|
||||
if (rlc->lcn == LCN_RL_NOT_MAPPED)
|
||||
continue;
|
||||
if (rlc->lcn != LCN_HOLE) {
|
||||
ntfs_log_trace("Received unmapped runlist.\n");
|
||||
errno = EINVAL;
|
||||
ntfs_log_trace("Bad runlist.\n");
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue