summaryrefslogtreecommitdiff
path: root/fs/ntfs3
diff options
context:
space:
mode:
authorKari Argillander <kari.argillander@gmail.com>2021-09-02 18:40:48 +0300
committerKonstantin Komarov <almaz.alexandrovich@paragon-software.com>2021-09-13 19:41:46 +0300
commit162333efa8dc4984d2ca0a2eb85528e13366f271 (patch)
treec0dec74d805acf86be80430adb82cea0105668cd /fs/ntfs3
parent9c2aadd0fdf88a7ebeebd1e97a9c66b07ad3e14a (diff)
fs/ntfs3: Limit binary search table size
Current binary search allocates memory for table and fill whole table before we start actual binary search. This is quite inefficient because table fill will always be O(n). Also if table is huge we need to reallocate memory which is costly. This implementation use just stack memory and always when table is full we will check if last element is <= and if not start table fill again. The idea was that it would be same cost as table reallocation. Signed-off-by: Kari Argillander <kari.argillander@gmail.com> Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
Diffstat (limited to 'fs/ntfs3')
-rw-r--r--fs/ntfs3/index.c110
1 files changed, 41 insertions, 69 deletions
diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c
index 35b77c92e96d..a16256ab3e9f 100644
--- a/fs/ntfs3/index.c
+++ b/fs/ntfs3/index.c
@@ -677,98 +677,70 @@ static struct NTFS_DE *hdr_find_e(const struct ntfs_index *indx,
u32 off = le32_to_cpu(hdr->de_off);
#ifdef NTFS3_INDEX_BINARY_SEARCH
- int max_idx = 0, fnd, min_idx;
- int nslots = 64;
- u16 *offs;
+ struct NTFS_DE *found = NULL;
+ int min_idx = 0, mid_idx, max_idx = 0;
+ int diff2;
+ u16 offs[64];
if (end > 0x10000)
goto next;
- offs = kmalloc(sizeof(u16) * nslots, GFP_NOFS);
- if (!offs)
- goto next;
+fill_table:
+ if (off + sizeof(struct NTFS_DE) > end)
+ return NULL;
- /* Use binary search algorithm. */
-next1:
- if (off + sizeof(struct NTFS_DE) > end) {
- e = NULL;
- goto out1;
- }
e = Add2Ptr(hdr, off);
e_size = le16_to_cpu(e->size);
- if (e_size < sizeof(struct NTFS_DE) || off + e_size > end) {
- e = NULL;
- goto out1;
- }
-
- if (max_idx >= nslots) {
- u16 *ptr;
- int new_slots = ALIGN(2 * nslots, 8);
-
- ptr = kmalloc(sizeof(u16) * new_slots, GFP_NOFS);
- if (ptr)
- memcpy(ptr, offs, sizeof(u16) * max_idx);
- kfree(offs);
- offs = ptr;
- nslots = new_slots;
- if (!ptr)
- goto next;
- }
-
- /* Store entry table. */
- offs[max_idx] = off;
+ if (e_size < sizeof(struct NTFS_DE) || off + e_size > end)
+ return NULL;
if (!de_is_last(e)) {
+ offs[max_idx] = off;
off += e_size;
- max_idx += 1;
- goto next1;
- }
- /*
- * Table of pointers is created.
- * Use binary search to find entry that is <= to the search value.
- */
- fnd = -1;
- min_idx = 0;
+ max_idx++;
+ if (max_idx < ARRAY_SIZE(offs))
+ goto fill_table;
- while (min_idx <= max_idx) {
- int mid_idx = min_idx + ((max_idx - min_idx) >> 1);
- int diff2;
-
- e = Add2Ptr(hdr, offs[mid_idx]);
+ max_idx--;
+ }
- e_key_len = le16_to_cpu(e->key_size);
+binary_search:
+ e_key_len = le16_to_cpu(e->key_size);
- diff2 = (*cmp)(key, key_len, e + 1, e_key_len, ctx);
+ diff2 = (*cmp)(key, key_len, e + 1, e_key_len, ctx);
+ if (diff2 > 0) {
+ if (found) {
+ min_idx = mid_idx + 1;
+ } else {
+ if (de_is_last(e))
+ return NULL;
- if (!diff2) {
- *diff = 0;
- goto out1;
+ max_idx = 0;
+ goto fill_table;
}
-
- if (diff2 < 0) {
+ } else if (diff2 < 0) {
+ if (found)
max_idx = mid_idx - 1;
- fnd = mid_idx;
- if (!fnd)
- break;
- } else {
- min_idx = mid_idx + 1;
- }
- }
+ else
+ max_idx--;
- if (fnd == -1) {
- e = NULL;
- goto out1;
+ found = e;
+ } else {
+ *diff = 0;
+ return e;
}
- *diff = -1;
- e = Add2Ptr(hdr, offs[fnd]);
+ if (min_idx > max_idx) {
+ *diff = -1;
+ return found;
+ }
-out1:
- kfree(offs);
+ mid_idx = (min_idx + max_idx) >> 1;
+ e = Add2Ptr(hdr, offs[mid_idx]);
- return e;
+ goto binary_search;
#endif
next: