From f2e1ff96d21d7a91ec443ca72e1385de80103731 Mon Sep 17 00:00:00 2001 From: yura Date: Thu, 9 Nov 2006 21:19:11 +0000 Subject: [PATCH] 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. --- .cvsignore | 1 + ChangeLog | 1 + include/ntfs/support.h | 6 +-- libntfs/attrib.c | 85 ++++++++++++++++++++++++++---------------- libntfs/inode.c | 13 ++++--- 5 files changed, 66 insertions(+), 40 deletions(-) diff --git a/.cvsignore b/.cvsignore index acc1a924..2474e039 100644 --- a/.cvsignore +++ b/.cvsignore @@ -22,3 +22,4 @@ stamp-h.in ltconfig missing INSTALL +cscope.out diff --git a/ChangeLog b/ChangeLog index 49f8e2a9..3077b4e8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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. diff --git a/include/ntfs/support.h b/include/ntfs/support.h index dcd5de81..57725ff0 100644 --- a/include/ntfs/support.h +++ b/include/ntfs/support.h @@ -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. diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 21c89db6..a0b7d812 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -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; diff --git a/libntfs/inode.c b/libntfs/inode.c index 87710354..1f96c982 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -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);