Messages in this thread Patch in this message | | | Date | Wed, 17 Apr 2024 16:08:25 +0300 | Subject | [PATCH 09/11] fs/ntfs3: Optimize to store sorted attribute definition table | From | Konstantin Komarov <> |
| |
0x18 bytes instead of 0xa0
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com> --- fs/ntfs3/fsntfs.c | 60 ++++++++++++++++++++++++++++- fs/ntfs3/inode.c | 30 +++++++-------- fs/ntfs3/ntfs.h | 4 -- fs/ntfs3/ntfs_fs.h | 40 ++++++++++--------- fs/ntfs3/super.c | 95 +++++++++++++++------------------------------- fs/ntfs3/xattr.c | 6 +-- 6 files changed, 126 insertions(+), 109 deletions(-)
diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c index ae2ef5c11868..f9c60f3cadaf 100644 --- a/fs/ntfs3/fsntfs.c +++ b/fs/ntfs3/fsntfs.c @@ -2698,4 +2698,62 @@ int ntfs_set_label(struct ntfs_sb_info *sbi, u8 *label, int len) out: __putname(uni); return err; -} \ No newline at end of file +} + +/* + * Check $AttrDef content and store sorted small $AttrDef entries + */ +int ntfs_check_attr_def(struct ntfs_sb_info *sbi, + const struct ATTR_DEF_ENTRY *raw, u32 bytes) +{ + const struct ATTR_DEF_ENTRY *de_s; + struct ATTR_DEF_ENTRY_SMALL *de_d; + u32 i, j; + u32 max_attr_type; + u32 n = (bytes / sizeof(*raw)) * sizeof(*raw); + + for (i = 0, max_attr_type = 0, de_s = raw; i < n; i++, de_s++) { + u64 sz; + u32 attr_type = le32_to_cpu(de_s->type); + + if (!attr_type) + break; + + if ((attr_type & 0xf) || (!i && ATTR_STD != de_s->type) || + (i && le32_to_cpu(de_s[-1].type) >= attr_type)) { + return -EINVAL; + } + + max_attr_type = attr_type; + + sz = le64_to_cpu(de_s->max_sz); + if (de_s->type == ATTR_REPARSE) + sbi->attrdef.rp_max_size = sz; + else if (de_s->type == ATTR_EA) + sbi->attrdef.ea_max_size = sz; + else if (de_s->type == ATTR_LABEL) + sbi->attrdef.label_max_size = sz; + } + + /* Last known attribute type is 0x100. */ + if (!max_attr_type || max_attr_type > 0x200) + return -EINVAL; + + n = max_attr_type >> 4; + sbi->attrdef.table = kcalloc(n, sizeof(*de_d), GFP_KERNEL); + if (!sbi->attrdef.table) + return -ENOMEM; + + for (j = 0, de_s = raw; j < i; j++, de_s++) { + u32 idx = (le32_to_cpu(de_s->type) >> 4) - 1; + de_d = sbi->attrdef.table + idx; + + de_d->type = de_s->type; + de_d->flags = de_s->flags; + de_d->min_sz = le64_to_cpu(de_s->min_sz); + de_d->max_sz = le64_to_cpu(de_s->max_sz); + } + sbi->attrdef.entries = n; + + return 0; +} diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index 94177c1dd818..ae4465bf099f 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -18,7 +18,7 @@ #include "ntfs_fs.h"
/* - * ntfs_read_mft - Read record and parses MFT. + * ntfs_read_mft - Read record and parse MFT. */ static struct inode *ntfs_read_mft(struct inode *inode, const struct cpu_str *name, @@ -1090,29 +1090,27 @@ int ntfs_flush_inodes(struct super_block *sb, struct inode *i1, return ret; }
-int inode_write_data(struct inode *inode, const void *data, size_t bytes) +/* + * Helper function to read file. + */ +int inode_read_data(struct inode *inode, void *data, size_t bytes) { pgoff_t idx; + struct address_space *mapping = inode->i_mapping;
- /* Write non resident data. */ for (idx = 0; bytes; idx++) { size_t op = bytes > PAGE_SIZE ? PAGE_SIZE : bytes; - struct page *page = ntfs_map_page(inode->i_mapping, idx); + struct page *page = read_mapping_page(mapping, idx, NULL); + void *kaddr;
if (IS_ERR(page)) return PTR_ERR(page);
- lock_page(page); - WARN_ON(!PageUptodate(page)); - ClearPageUptodate(page); - - memcpy(page_address(page), data, op); - - flush_dcache_page(page); - SetPageUptodate(page); - unlock_page(page); + kaddr = kmap_atomic(page); + memcpy(data, kaddr, op); + kunmap_atomic(kaddr);
- ntfs_unmap_page(page); + put_page(page);
bytes -= op; data = Add2Ptr(data, PAGE_SIZE); @@ -1160,7 +1158,7 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname, /* err = the length of unicode name of symlink. */ *nsize = ntfs_reparse_bytes(err);
- if (*nsize > sbi->reparse.max_size) { + if (*nsize > sbi->attrdef.rp_max_size) { err = -EFBIG; goto out; } @@ -1954,7 +1952,7 @@ static noinline int ntfs_readlink_hlp(const struct dentry *link_de, rp = NULL; }
- if (size > sbi->reparse.max_size || size <= sizeof(u32)) + if (size > sbi->attrdef.rp_max_size || size <= sizeof(u32)) goto out;
if (!rp) { diff --git a/fs/ntfs3/ntfs.h b/fs/ntfs3/ntfs.h index 3d6143c7abc0..1dd03ba1dc93 100644 --- a/fs/ntfs3/ntfs.h +++ b/fs/ntfs3/ntfs.h @@ -817,7 +817,6 @@ struct VOLUME_INFO {
#define SIZEOF_ATTRIBUTE_VOLUME_INFO 0xc
-#define NTFS_LABEL_MAX_LENGTH (0x100 / sizeof(short)) #define NTFS_ATTR_INDEXABLE cpu_to_le32(0x00000002) #define NTFS_ATTR_DUPALLOWED cpu_to_le32(0x00000004) #define NTFS_ATTR_MUST_BE_INDEXED cpu_to_le32(0x00000010) @@ -1002,9 +1001,6 @@ struct REPARSE_POINT {
static_assert(sizeof(struct REPARSE_POINT) == 0x18);
-/* Maximum allowed size of the reparse data. */ -#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024) - /* * The value of the following constant needs to satisfy the following * conditions: diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 00dec0ec5648..1d4fb6f87dea 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -201,6 +201,15 @@ struct ntfs_index { u8 type; // index_mutex_classed };
+/* NOT ondisk!. Just a small copy of $AttrDef file entry. */ +struct ATTR_DEF_ENTRY_SMALL { + enum ATTR_TYPE type; + __le32 flags; + u64 min_sz; + u64 max_sz; +}; +static_assert(sizeof(struct ATTR_DEF_ENTRY_SMALL) == 0x18); + /* Minimum MFT zone. */ #define NTFS_MIN_MFT_ZONE 100 /* Step to increase the MFT. */ @@ -242,9 +251,13 @@ struct ntfs_sb_info { CLST reparse_no; CLST usn_jrnl_no;
- struct ATTR_DEF_ENTRY *def_table; // Attribute definition table. - u32 def_entries; - u32 ea_max_size; + struct { + u64 rp_max_size; // 16K + u32 entries; + u32 ea_max_size; + u32 label_max_size; + struct ATTR_DEF_ENTRY_SMALL *table; // 'entries'. + } attrdef;
struct MFT_REC *new_rec;
@@ -296,7 +309,6 @@ struct ntfs_sb_info { struct { struct ntfs_index index_r; struct ntfs_inode *ni; - u64 max_size; // 16K } reparse;
struct { @@ -658,6 +670,8 @@ int run_deallocate(struct ntfs_sb_info *sbi, const struct runs_tree *run, bool trim); bool valid_windows_name(struct ntfs_sb_info *sbi, const struct le_str *name); int ntfs_set_label(struct ntfs_sb_info *sbi, u8 *label, int len); +int ntfs_check_attr_def(struct ntfs_sb_info *sbi, + const struct ATTR_DEF_ENTRY *raw, u32 bytes);
/* Globals from index.c */ int indx_used_bit(struct ntfs_index *indx, struct ntfs_inode *ni, size_t *bit); @@ -714,7 +728,7 @@ int ntfs3_write_inode(struct inode *inode, struct writeback_control *wbc); int ntfs_sync_inode(struct inode *inode); int ntfs_flush_inodes(struct super_block *sb, struct inode *i1, struct inode *i2); -int inode_write_data(struct inode *inode, const void *data, size_t bytes); +int inode_read_data(struct inode *inode, void *data, size_t bytes); int ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, const struct cpu_str *uni, umode_t mode, dev_t dev, const char *symname, u32 size, @@ -908,22 +922,6 @@ static inline bool ntfs_is_meta_file(struct ntfs_sb_info *sbi, CLST rno) rno == sbi->usn_jrnl_no; }
-static inline void ntfs_unmap_page(struct page *page) -{ - kunmap(page); - put_page(page); -} - -static inline struct page *ntfs_map_page(struct address_space *mapping, - unsigned long index) -{ - struct page *page = read_mapping_page(mapping, index, NULL); - - if (!IS_ERR(page)) - kmap(page); - return page; -} - static inline size_t wnd_zone_bit(const struct wnd_bitmap *wnd) { return wnd->zone_bit; diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index ac4722011140..8beefbca5769 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -624,7 +624,7 @@ static void ntfs3_free_sbi(struct ntfs_sb_info *sbi) { kfree(sbi->new_rec); kvfree(ntfs_put_shared(sbi->upcase)); - kvfree(sbi->def_table); + kfree(sbi->attrdef.table); kfree(sbi->compress.lznt); #ifdef CONFIG_NTFS3_LZX_XPRESS xpress_free_decompressor(sbi->compress.xpress); @@ -1157,8 +1157,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) CLST vcn, lcn, len; struct ATTRIB *attr; const struct VOLUME_INFO *info; - u32 idx, done, bytes; - struct ATTR_DEF_ENTRY *t; u16 *shared; struct MFT_REF ref; bool ro = sb_rdonly(sb); @@ -1199,7 +1197,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
/* * Load $Volume. This should be done before $LogFile - * 'cause 'sbi->volume.ni' is used 'ntfs_set_state'. + * 'cause 'sbi->volume.ni' is used in 'ntfs_set_state'. */ ref.low = cpu_to_le32(MFT_REC_VOL); ref.seq = cpu_to_le16(MFT_REC_VOL); @@ -1422,54 +1420,28 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) goto put_inode_out; }
- bytes = inode->i_size; - sbi->def_table = t = kvmalloc(bytes, GFP_KERNEL); - if (!t) { - err = -ENOMEM; - goto put_inode_out; - } - - for (done = idx = 0; done < bytes; done += PAGE_SIZE, idx++) { - unsigned long tail = bytes - done; - struct page *page = ntfs_map_page(inode->i_mapping, idx); - - if (IS_ERR(page)) { - err = PTR_ERR(page); - ntfs_err(sb, "Failed to read $AttrDef (%d).", err); + { + u32 bytes = inode->i_size; + struct ATTR_DEF_ENTRY *def_table = kmalloc(bytes, GFP_KERNEL); + if (!def_table) { + err = -ENOMEM; goto put_inode_out; } - memcpy(Add2Ptr(t, done), page_address(page), - min(PAGE_SIZE, tail)); - ntfs_unmap_page(page);
- if (!idx && ATTR_STD != t->type) { - ntfs_err(sb, "$AttrDef is corrupted."); - err = -EINVAL; - goto put_inode_out; + /* Read the entire file. */ + err = inode_read_data(inode, def_table, bytes); + if (err) { + ntfs_err(sb, "Failed to read $AttrDef (%d).", err); + } else { + /* Check content and store sorted array. */ + err = ntfs_check_attr_def(sbi, def_table, bytes); + if (err) + ntfs_err(sb, "$AttrDef is corrupted."); } - } - - t += 1; - sbi->def_entries = 1; - done = sizeof(struct ATTR_DEF_ENTRY); - sbi->reparse.max_size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; - sbi->ea_max_size = 0x10000; /* default formatter value */ - - while (done + sizeof(struct ATTR_DEF_ENTRY) <= bytes) { - u32 t32 = le32_to_cpu(t->type); - u64 sz = le64_to_cpu(t->max_sz); - - if ((t32 & 0xF) || le32_to_cpu(t[-1].type) >= t32) - break; - - if (t->type == ATTR_REPARSE) - sbi->reparse.max_size = sz; - else if (t->type == ATTR_EA) - sbi->ea_max_size = sz;
- done += sizeof(struct ATTR_DEF_ENTRY); - t += 1; - sbi->def_entries += 1; + kfree(def_table); + if (err) + goto put_inode_out; } iput(inode);
@@ -1489,27 +1461,22 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) goto put_inode_out; }
- for (idx = 0; idx < (0x10000 * sizeof(short) >> PAGE_SHIFT); idx++) { - const __le16 *src; - u16 *dst = Add2Ptr(sbi->upcase, idx << PAGE_SHIFT); - struct page *page = ntfs_map_page(inode->i_mapping, idx); - - if (IS_ERR(page)) { - err = PTR_ERR(page); - ntfs_err(sb, "Failed to read $UpCase (%d).", err); - goto put_inode_out; - } - - src = page_address(page); + /* Read the entire file. */ + err = inode_read_data(inode, sbi->upcase, 0x10000 * sizeof(short)); + if (err) { + ntfs_err(sb, "Failed to read $UpCase (%d).", err); + goto put_inode_out; + }
#ifdef __BIG_ENDIAN - for (i = 0; i < PAGE_SIZE / sizeof(u16); i++) + { + const __le16 *src = sbi->upcase; + u16 *dst = sbi->upcase; + + for (i = 0; i < 0x10000; i++) *dst++ = le16_to_cpu(*src++); -#else - memcpy(dst, src, PAGE_SIZE); -#endif - ntfs_unmap_page(page); } +#endif
shared = ntfs_set_shared(sbi->upcase, 0x10000 * sizeof(short)); if (shared && sbi->upcase != shared) { diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index 872df2197202..a7f122e51c04 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -99,12 +99,12 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,
/* Check Ea limit. */ size = le32_to_cpu((*info)->size); - if (size > sbi->ea_max_size) { + if (size > sbi->attrdef.ea_max_size) { err = -EFBIG; goto out; }
- if (attr_size(attr_ea) > sbi->ea_max_size) { + if (attr_size(attr_ea) > sbi->attrdef.ea_max_size) { err = -EFBIG; goto out; } @@ -430,7 +430,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name, * 1. Check ea_info.size_pack for overflow. * 2. New attribute size must fit value from $AttrDef */ - if (new_pack > 0xffff || size > sbi->ea_max_size) { + if (new_pack > 0xffff || size > sbi->attrdef.ea_max_size) { ntfs_inode_warn( inode, "The size of extended attributes must not exceed 64KiB"); -- 2.34.1
| |