Spent really a lot of time applying various "optimizations" from ntfs-3g and
finally figured out that ntfs-3g is faster than ntfsmount only because of 3 reasons: 1) turned on noatime option by default 2) ntfs-3g builds without debug output by default 3) the only real optimization: almost always add resident attributes. However by accident patch in ntfs-3g for 3) breaks several code paths (why I am not surprised?), thus I rewrote whole ntfs_attr_add() logic.edge.strict_endians
parent
025f07a269
commit
f2e1ff96d2
|
@ -22,3 +22,4 @@ stamp-h.in
|
|||
ltconfig
|
||||
missing
|
||||
INSTALL
|
||||
cscope.out
|
||||
|
|
|
@ -65,6 +65,7 @@ xx/xx/2006 - x.xx.x - .
|
|||
- Factor ntfs_attr_fill_hole() out of ntfs_attr_pwrite(). (Szaka)
|
||||
- ntfsmount: require FUSE version >= 2.6.0 for build. Fixes fusermount
|
||||
lookup problem and allows to drop compatibility code. (Yura)
|
||||
- Rewrite ntfs_attr_add() algorithm. (Yura)
|
||||
|
||||
21/06/2006 - 1.13.1 - Various fixes.
|
||||
|
||||
|
|
|
@ -71,9 +71,9 @@
|
|||
/*
|
||||
* Round up and down @num to 2 in power of @order.
|
||||
*/
|
||||
#define ROUND_UP(num,order) (((num) + ((1 << order) - 1)) & \
|
||||
~((1 << order) - 1))
|
||||
#define ROUND_DOWN(num,order) ((num) & ~((1 << order) - 1))
|
||||
#define ROUND_UP(num,order) (((num) + ((1 << (order)) - 1)) & \
|
||||
~((1 << (order)) - 1))
|
||||
#define ROUND_DOWN(num,order) ((num) & ~((1 << (order)) - 1))
|
||||
|
||||
/*
|
||||
* Simple bit operation macros. NOTE: These are NOT atomic.
|
||||
|
|
|
@ -2946,7 +2946,8 @@ int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
|
|||
{
|
||||
u32 attr_rec_size;
|
||||
int err, i, offset;
|
||||
BOOL is_resident;
|
||||
BOOL is_resident = TRUE;
|
||||
BOOL always_non_resident = FALSE, always_resident = FALSE;
|
||||
ntfs_inode *attr_ni;
|
||||
ntfs_attr *na;
|
||||
|
||||
|
@ -2993,38 +2994,29 @@ int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
|
|||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
always_resident = TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine resident or not will be new attribute. We add 8 to size in
|
||||
* non resident case for mapping pairs.
|
||||
*/
|
||||
if (!ntfs_attr_can_be_resident(ni->vol, type)) {
|
||||
/* Attribute can be resident. */
|
||||
is_resident = TRUE;
|
||||
/* Check if it is better to make attribute non resident. */
|
||||
if (!ntfs_attr_can_be_non_resident(ni->vol, type) &&
|
||||
offsetof(ATTR_RECORD, resident_end) + size >=
|
||||
offsetof(ATTR_RECORD, non_resident_end) + 8)
|
||||
/* Make it non resident. */
|
||||
is_resident = FALSE;
|
||||
} else {
|
||||
/* Check whether attribute can be resident. */
|
||||
if (ntfs_attr_can_be_resident(ni->vol, type)) {
|
||||
if (errno != EPERM) {
|
||||
err = errno;
|
||||
ntfs_log_trace("ntfs_attr_can_be_resident failed.\n");
|
||||
ntfs_log_trace("ntfs_attr_can_be_resident() failed.\n");
|
||||
goto err_out;
|
||||
}
|
||||
/* Attribute can't be resident. */
|
||||
is_resident = FALSE;
|
||||
always_non_resident = TRUE;
|
||||
}
|
||||
|
||||
retry:
|
||||
/* Calculate attribute record size. */
|
||||
if (is_resident)
|
||||
attr_rec_size = offsetof(ATTR_RECORD, resident_end) +
|
||||
((name_len * sizeof(ntfschar) + 7) & ~7) +
|
||||
((size + 7) & ~7);
|
||||
else
|
||||
ROUND_UP(name_len * sizeof(ntfschar), 3) +
|
||||
ROUND_UP(size, 3);
|
||||
else /* We add 8 for space for mapping pairs. */
|
||||
attr_rec_size = offsetof(ATTR_RECORD, non_resident_end) +
|
||||
((name_len * sizeof(ntfschar) + 7) & ~7) + 8;
|
||||
ROUND_UP(name_len * sizeof(ntfschar), 3) + 8;
|
||||
|
||||
/*
|
||||
* If we have enough free space for the new attribute in the base MFT
|
||||
|
@ -3050,6 +3042,20 @@ int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
|
|||
goto add_attr_record;
|
||||
}
|
||||
|
||||
/*
|
||||
* If failed to find space for resident attribute, then try to find
|
||||
* space for non resident one.
|
||||
*/
|
||||
if (is_resident && !always_resident) {
|
||||
is_resident = FALSE;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: Try to make other attributes non-resident here. Factor out
|
||||
* code from ntfs_resident_attr_resize.
|
||||
*/
|
||||
|
||||
/* There is no extent that contain enough space for new attribute. */
|
||||
if (!NInoAttrList(ni)) {
|
||||
/* Add attribute list not present, add it and retry. */
|
||||
|
@ -3060,7 +3066,7 @@ int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
|
|||
}
|
||||
return ntfs_attr_add(ni, type, name, name_len, val, size);
|
||||
}
|
||||
/* Allocate new extent. */
|
||||
/* Allocate new extent for attribute. */
|
||||
attr_ni = ntfs_mft_record_alloc(ni->vol, ni);
|
||||
if (!attr_ni) {
|
||||
err = errno;
|
||||
|
@ -3068,6 +3074,21 @@ int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
|
|||
goto err_out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine resident or not will be attribute using heuristics and
|
||||
* calculate attribute record size. FIXME: small code duplication here.
|
||||
*/
|
||||
if (always_resident || (!always_non_resident && size < 256)) {
|
||||
is_resident = TRUE;
|
||||
attr_rec_size = offsetof(ATTR_RECORD, resident_end) +
|
||||
ROUND_UP(name_len * sizeof(ntfschar), 3) +
|
||||
ROUND_UP(size, 3);
|
||||
} else { /* We add 8 for space for mapping pairs. */
|
||||
is_resident = FALSE;
|
||||
attr_rec_size = offsetof(ATTR_RECORD, non_resident_end) +
|
||||
ROUND_UP(name_len * sizeof(ntfschar), 3) + 8;
|
||||
}
|
||||
|
||||
add_attr_record:
|
||||
if (is_resident) {
|
||||
/* Add resident attribute. */
|
||||
|
@ -3698,14 +3719,14 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize)
|
|||
if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) {
|
||||
err = errno;
|
||||
if (err == ERANGE) {
|
||||
ntfs_log_trace("Eeek! Size bounds check failed. "
|
||||
ntfs_log_trace("Size bounds check failed. "
|
||||
"Aborting...\n");
|
||||
} else if (err == ENOENT)
|
||||
err = EIO;
|
||||
goto put_err_out;
|
||||
}
|
||||
/*
|
||||
* If @newsize is bigger than the mft record we need to make the
|
||||
* If @newsize is bigger than the MFT record we need to make the
|
||||
* attribute non-resident if the attribute type supports it. If it is
|
||||
* smaller we can go ahead and attempt the resize.
|
||||
*/
|
||||
|
@ -3715,7 +3736,7 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize)
|
|||
newsize)) {
|
||||
/* Update attribute size everywhere. */
|
||||
na->data_size = na->initialized_size = newsize;
|
||||
na->allocated_size = (newsize + 7) & ~7;
|
||||
na->allocated_size = ROUND_UP(newsize, 3);
|
||||
if (NAttrCompressed(na) || NAttrSparse(na))
|
||||
na->compressed_size = na->allocated_size;
|
||||
if (na->type == AT_DATA && na->name == AT_UNNAMED) {
|
||||
|
@ -3728,12 +3749,12 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize)
|
|||
/* Error! If not enough space, just continue. */
|
||||
if (errno != ENOSPC) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Eeek! Failed to resize resident part "
|
||||
ntfs_log_trace("Failed to resize resident part "
|
||||
"of attribute. Aborting...\n");
|
||||
goto put_err_out;
|
||||
}
|
||||
}
|
||||
/* There is not enough space in the mft record to perform the resize. */
|
||||
/* There is not enough space in the MFT record to perform the resize. */
|
||||
|
||||
/* Make the attribute non-resident if possible. */
|
||||
if (!ntfs_attr_make_non_resident(na, ctx)) {
|
||||
|
@ -3743,7 +3764,7 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize)
|
|||
return ntfs_attr_truncate(na, newsize);
|
||||
} else if (errno != ENOSPC && errno != EPERM) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Eeek! Failed to make attribute non-resident. "
|
||||
ntfs_log_trace("Failed to make attribute non-resident. "
|
||||
"Aborting...\n");
|
||||
goto put_err_out;
|
||||
}
|
||||
|
@ -3763,8 +3784,8 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize)
|
|||
* pairs will take 8 bytes.
|
||||
*/
|
||||
if (le32_to_cpu(a->length) <= offsetof(ATTR_RECORD,
|
||||
compressed_size) + ((a->name_length *
|
||||
sizeof(ntfschar) + 7) & ~7) + 8)
|
||||
compressed_size) + ROUND_UP(a->name_length *
|
||||
sizeof(ntfschar), 3) + 8)
|
||||
continue;
|
||||
|
||||
tna = ntfs_attr_open(na->ni, a->type, (ntfschar*)((u8*)a +
|
||||
|
@ -3804,7 +3825,7 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize)
|
|||
}
|
||||
|
||||
/*
|
||||
* Move the attribute to a new mft record, creating an attribute list
|
||||
* Move the attribute to a new MFT record, creating an attribute list
|
||||
* attribute or modifying it if it is already present.
|
||||
*/
|
||||
|
||||
|
@ -3855,7 +3876,7 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize)
|
|||
return -1;
|
||||
return ntfs_resident_attr_resize(na, newsize);
|
||||
}
|
||||
/* Allocate new mft record. */
|
||||
/* Allocate new MFT record. */
|
||||
ni = ntfs_mft_record_alloc(vol, ni);
|
||||
if (!ni) {
|
||||
err = errno;
|
||||
|
|
|
@ -354,7 +354,8 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref)
|
|||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
ntfs_log_trace("Opening extent inode 0x%llx (base mft record 0x%llx).\n",
|
||||
ntfs_log_trace("Opening extent inode 0x%llx "
|
||||
"(base MFT record 0x%llx).\n",
|
||||
(unsigned long long)mft_no,
|
||||
(unsigned long long)base_ni->mft_no);
|
||||
/* Is the extent inode already open and attached to the base inode? */
|
||||
|
@ -370,8 +371,9 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref)
|
|||
seq_no = MSEQNO_LE(mref);
|
||||
if (seq_no && seq_no != le16_to_cpu(
|
||||
ni->mrec->sequence_number)) {
|
||||
ntfs_log_debug("Found stale extent mft reference! "
|
||||
"Corrupt file system. Run chkdsk.\n");
|
||||
ntfs_log_debug("Found stale extent mft "
|
||||
"reference! Corrupt file "
|
||||
"system. Run chkdsk.\n");
|
||||
errno = EIO;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -440,7 +442,7 @@ int ntfs_inode_attach_all_extents(ntfs_inode *ni)
|
|||
return 0;
|
||||
|
||||
if (!ni->attr_list) {
|
||||
ntfs_log_trace("Corrupt in-memory struct.\n");
|
||||
ntfs_log_trace("Corrupted in-memory structure.\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
@ -453,7 +455,8 @@ int ntfs_inode_attach_all_extents(ntfs_inode *ni)
|
|||
prev_attached != MREF_LE(ale->mft_reference)) {
|
||||
if (!ntfs_extent_inode_open(ni,
|
||||
MREF_LE(ale->mft_reference))) {
|
||||
ntfs_log_trace("Couldn't attach extent inode.\n");
|
||||
ntfs_log_trace("Couldn't attach extent "
|
||||
"inode.\n");
|
||||
return -1;
|
||||
}
|
||||
prev_attached = MREF_LE(ale->mft_reference);
|
||||
|
|
Loading…
Reference in New Issue