diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/buflib.c | 5 | ||||
-rw-r--r-- | firmware/common/dircache.c | 114 | ||||
-rw-r--r-- | firmware/core_alloc.c | 1 |
3 files changed, 85 insertions, 35 deletions
diff --git a/firmware/buflib.c b/firmware/buflib.c index 51cf86bf5b..880357ccf4 100644 --- a/firmware/buflib.c +++ b/firmware/buflib.c | |||
@@ -192,10 +192,6 @@ handle_table_shrink(struct buflib_context *ctx) | |||
192 | static bool | 192 | static bool |
193 | move_block(struct buflib_context* ctx, union buflib_data* block, int shift) | 193 | move_block(struct buflib_context* ctx, union buflib_data* block, int shift) |
194 | { | 194 | { |
195 | #if 1 /* moving temporarily disabled */ | ||
196 | (void)ctx;(void)block;(void)shift; | ||
197 | return false; | ||
198 | #else | ||
199 | char* new_start; | 195 | char* new_start; |
200 | union buflib_data *new_block, *tmp = block[1].handle; | 196 | union buflib_data *new_block, *tmp = block[1].handle; |
201 | struct buflib_callbacks *ops = block[2].ops; | 197 | struct buflib_callbacks *ops = block[2].ops; |
@@ -218,7 +214,6 @@ move_block(struct buflib_context* ctx, union buflib_data* block, int shift) | |||
218 | memmove(new_block, block, block->val * sizeof(union buflib_data)); | 214 | memmove(new_block, block, block->val * sizeof(union buflib_data)); |
219 | 215 | ||
220 | return true; | 216 | return true; |
221 | #endif | ||
222 | } | 217 | } |
223 | 218 | ||
224 | /* Compact allocations and handle table, adjusting handle pointers as needed. | 219 | /* Compact allocations and handle table, adjusting handle pointers as needed. |
diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c index 334801ce57..6b2260def3 100644 --- a/firmware/common/dircache.c +++ b/firmware/common/dircache.c | |||
@@ -66,12 +66,21 @@ struct fdbind_queue { | |||
66 | int fd; | 66 | int fd; |
67 | }; | 67 | }; |
68 | 68 | ||
69 | /* Exported structures. */ | 69 | /* Unions with char to make pointer arithmetic simpler and avoid casting */ |
70 | struct dircache_entry { | 70 | struct dircache_entry { |
71 | struct dirinfo info; | 71 | struct dirinfo info; |
72 | struct dircache_entry *next; | 72 | union { |
73 | struct dircache_entry *up; | 73 | struct dircache_entry *next; |
74 | struct dircache_entry *down; | 74 | char* next_char; |
75 | }; | ||
76 | union { | ||
77 | struct dircache_entry *up; | ||
78 | char* up_char; | ||
79 | }; | ||
80 | union { | ||
81 | struct dircache_entry *down; | ||
82 | char* down_char; | ||
83 | }; | ||
75 | long startcluster; | 84 | long startcluster; |
76 | char *d_name; | 85 | char *d_name; |
77 | }; | 86 | }; |
@@ -130,6 +139,44 @@ static inline struct dircache_entry* get_entry(int id) | |||
130 | return &dircache_root[id]; | 139 | return &dircache_root[id]; |
131 | } | 140 | } |
132 | 141 | ||
142 | /* flag to make sure buffer doesn't move due to other allocs. | ||
143 | * this is set to true completely during dircache build */ | ||
144 | static bool dont_move = false; | ||
145 | static int dircache_handle; | ||
146 | static int move_callback(int handle, void* current, void* new) | ||
147 | { | ||
148 | (void)handle; | ||
149 | if (dont_move) | ||
150 | return BUFLIB_CB_CANNOT_MOVE; | ||
151 | |||
152 | /* relocate the cache */ | ||
153 | ptrdiff_t diff = new - current; | ||
154 | for(unsigned i = 0; i < entry_count; i++) | ||
155 | { | ||
156 | if (dircache_root[i].d_name) | ||
157 | dircache_root[i].d_name += diff; | ||
158 | if (dircache_root[i].next_char) | ||
159 | dircache_root[i].next_char += diff; | ||
160 | if (dircache_root[i].up_char) | ||
161 | dircache_root[i].up_char += diff; | ||
162 | if (dircache_root[i].down_char) | ||
163 | dircache_root[i].down_char += diff; | ||
164 | } | ||
165 | dircache_root = new; | ||
166 | |||
167 | d_names_start -= diff; | ||
168 | d_names_end -= diff; | ||
169 | dot -= diff; | ||
170 | dotdot -= diff; | ||
171 | |||
172 | return BUFLIB_CB_OK; | ||
173 | } | ||
174 | |||
175 | static struct buflib_callbacks ops = { | ||
176 | .move_callback = move_callback, | ||
177 | .shrink_callback = NULL, | ||
178 | }; | ||
179 | |||
133 | #ifdef HAVE_EEPROM_SETTINGS | 180 | #ifdef HAVE_EEPROM_SETTINGS |
134 | /** | 181 | /** |
135 | * Open the dircache file to save a snapshot on disk | 182 | * Open the dircache file to save a snapshot on disk |
@@ -573,10 +620,11 @@ int dircache_load(void) | |||
573 | } | 620 | } |
574 | 621 | ||
575 | allocated_size = maindata.size + DIRCACHE_RESERVE; | 622 | allocated_size = maindata.size + DIRCACHE_RESERVE; |
576 | int handle = core_alloc("dircache", allocated_size); | 623 | dircache_handle = core_alloc_ex("dircache", allocated_size, &ops); |
577 | dircache_root = core_get_data(handle); | 624 | /* block movement during upcoming I/O */ |
578 | /* needs to be struct-size aligned so that the pointer arithmetic below works */ | 625 | dont_move = true; |
579 | ALIGN_BUFFER(dircache_root, allocated_size, sizeof(struct dircache_entry)); | 626 | dircache_root = core_get_data(dircache_handle); |
627 | ALIGN_BUFFER(dircache_root, allocated_size, sizeof(struct dircache_entry*)); | ||
580 | entry_count = maindata.entry_count; | 628 | entry_count = maindata.entry_count; |
581 | appflags = maindata.appflags; | 629 | appflags = maindata.appflags; |
582 | 630 | ||
@@ -608,8 +656,9 @@ int dircache_load(void) | |||
608 | dotdot = dot - sizeof(".."); | 656 | dotdot = dot - sizeof(".."); |
609 | 657 | ||
610 | /* d_names are in reverse order, so the last entry points to the first string */ | 658 | /* d_names are in reverse order, so the last entry points to the first string */ |
611 | ptrdiff_t offset_d_names = maindata.d_names_start - d_names_start, | 659 | ptrdiff_t offset_d_names = maindata.d_names_start - d_names_start; |
612 | offset_entries = maindata.root_entry - dircache_root; | 660 | ptrdiff_t offset_entries = maindata.root_entry - dircache_root; |
661 | offset_entries *= sizeof(struct dircache_entry); /* make it bytes */ | ||
613 | 662 | ||
614 | /* offset_entries is less likely to differ, so check if it's 0 in the loop | 663 | /* offset_entries is less likely to differ, so check if it's 0 in the loop |
615 | * offset_d_names however is almost always non-zero, since dircache_save() | 664 | * offset_d_names however is almost always non-zero, since dircache_save() |
@@ -625,12 +674,12 @@ int dircache_load(void) | |||
625 | 674 | ||
626 | if (offset_entries == 0) | 675 | if (offset_entries == 0) |
627 | continue; | 676 | continue; |
628 | if (dircache_root[i].next) | 677 | if (dircache_root[i].next_char) |
629 | dircache_root[i].next -= offset_entries; | 678 | dircache_root[i].next_char -= offset_entries; |
630 | if (dircache_root[i].up) | 679 | if (dircache_root[i].up_char) |
631 | dircache_root[i].up -= offset_entries; | 680 | dircache_root[i].up_char -= offset_entries; |
632 | if (dircache_root[i].down) | 681 | if (dircache_root[i].down_char) |
633 | dircache_root[i].down -= offset_entries; | 682 | dircache_root[i].down_char -= offset_entries; |
634 | } | 683 | } |
635 | } | 684 | } |
636 | 685 | ||
@@ -640,6 +689,7 @@ int dircache_load(void) | |||
640 | logf("Done, %ld KiB used", dircache_size / 1024); | 689 | logf("Done, %ld KiB used", dircache_size / 1024); |
641 | dircache_initialized = true; | 690 | dircache_initialized = true; |
642 | memset(fd_bindings, 0, sizeof(fd_bindings)); | 691 | memset(fd_bindings, 0, sizeof(fd_bindings)); |
692 | dont_move = false; | ||
643 | 693 | ||
644 | return 0; | 694 | return 0; |
645 | } | 695 | } |
@@ -660,6 +710,7 @@ int dircache_save(void) | |||
660 | return -1; | 710 | return -1; |
661 | 711 | ||
662 | logf("Saving directory cache"); | 712 | logf("Saving directory cache"); |
713 | dont_move = true; | ||
663 | fd = open_dircache_file(O_WRONLY | O_CREAT | O_TRUNC, 0666); | 714 | fd = open_dircache_file(O_WRONLY | O_CREAT | O_TRUNC, 0666); |
664 | 715 | ||
665 | maindata.magic = DIRCACHE_MAGIC; | 716 | maindata.magic = DIRCACHE_MAGIC; |
@@ -698,7 +749,7 @@ int dircache_save(void) | |||
698 | return -4; | 749 | return -4; |
699 | } | 750 | } |
700 | 751 | ||
701 | 752 | dont_move = false; | |
702 | return 0; | 753 | return 0; |
703 | } | 754 | } |
704 | #endif /* HAVE_EEPROM_SETTINGS */ | 755 | #endif /* HAVE_EEPROM_SETTINGS */ |
@@ -720,6 +771,7 @@ static int dircache_do_rebuild(void) | |||
720 | /* reset dircache and alloc root entry */ | 771 | /* reset dircache and alloc root entry */ |
721 | entry_count = 0; | 772 | entry_count = 0; |
722 | root_entry = allocate_entry(); | 773 | root_entry = allocate_entry(); |
774 | dont_move = true; | ||
723 | 775 | ||
724 | #ifdef HAVE_MULTIVOLUME | 776 | #ifdef HAVE_MULTIVOLUME |
725 | append_position = root_entry; | 777 | append_position = root_entry; |
@@ -740,6 +792,7 @@ static int dircache_do_rebuild(void) | |||
740 | cpu_boost(false); | 792 | cpu_boost(false); |
741 | dircache_size = 0; | 793 | dircache_size = 0; |
742 | dircache_initializing = false; | 794 | dircache_initializing = false; |
795 | dont_move = false; | ||
743 | return -2; | 796 | return -2; |
744 | } | 797 | } |
745 | cpu_boost(false); | 798 | cpu_boost(false); |
@@ -765,7 +818,8 @@ static int dircache_do_rebuild(void) | |||
765 | if (allocated_size - dircache_size < DIRCACHE_RESERVE) | 818 | if (allocated_size - dircache_size < DIRCACHE_RESERVE) |
766 | reserve_used = DIRCACHE_RESERVE - (allocated_size - dircache_size); | 819 | reserve_used = DIRCACHE_RESERVE - (allocated_size - dircache_size); |
767 | } | 820 | } |
768 | 821 | ||
822 | dont_move = false; | ||
769 | return 1; | 823 | return 1; |
770 | } | 824 | } |
771 | 825 | ||
@@ -790,7 +844,8 @@ static void dircache_thread(void) | |||
790 | #endif | 844 | #endif |
791 | case DIRCACHE_BUILD: | 845 | case DIRCACHE_BUILD: |
792 | thread_enabled = true; | 846 | thread_enabled = true; |
793 | dircache_do_rebuild(); | 847 | if (dircache_do_rebuild() < 0) |
848 | core_free(dircache_handle); | ||
794 | thread_enabled = false; | 849 | thread_enabled = false; |
795 | break ; | 850 | break ; |
796 | 851 | ||
@@ -848,11 +903,10 @@ int dircache_build(int last_size) | |||
848 | 903 | ||
849 | if (last_size > DIRCACHE_RESERVE && last_size < DIRCACHE_LIMIT ) | 904 | if (last_size > DIRCACHE_RESERVE && last_size < DIRCACHE_LIMIT ) |
850 | { | 905 | { |
851 | int handle; | ||
852 | allocated_size = last_size + DIRCACHE_RESERVE; | 906 | allocated_size = last_size + DIRCACHE_RESERVE; |
853 | handle = core_alloc("dircache", allocated_size); | 907 | dircache_handle = core_alloc_ex("dircache", allocated_size, &ops); |
854 | dircache_root = core_get_data(handle); | 908 | dircache_root = core_get_data(dircache_handle); |
855 | ALIGN_BUFFER(dircache_root, allocated_size, sizeof(struct dircache_entry)); | 909 | ALIGN_BUFFER(dircache_root, allocated_size, sizeof(struct dircache_entry*)); |
856 | d_names_start = d_names_end = ((char*)dircache_root)+allocated_size-1; | 910 | d_names_start = d_names_end = ((char*)dircache_root)+allocated_size-1; |
857 | dircache_size = 0; | 911 | dircache_size = 0; |
858 | thread_enabled = true; | 912 | thread_enabled = true; |
@@ -869,10 +923,10 @@ int dircache_build(int last_size) | |||
869 | * after generation the buffer will be compacted with DIRCACHE_RESERVE | 923 | * after generation the buffer will be compacted with DIRCACHE_RESERVE |
870 | * free bytes inbetween */ | 924 | * free bytes inbetween */ |
871 | size_t got_size; | 925 | size_t got_size; |
872 | int handle = core_alloc_maximum("dircache", &got_size, NULL); | 926 | dircache_handle = core_alloc_maximum("dircache", &got_size, &ops); |
873 | char* buf = core_get_data(handle); | 927 | char* buf = core_get_data(dircache_handle); |
874 | dircache_root = (struct dircache_entry*)ALIGN_UP(buf, | 928 | dircache_root = (struct dircache_entry*)ALIGN_UP(buf, |
875 | sizeof(struct dircache_entry)); | 929 | sizeof(struct dircache_entry*)); |
876 | d_names_start = d_names_end = buf + got_size - 1; | 930 | d_names_start = d_names_end = buf + got_size - 1; |
877 | dircache_size = 0; | 931 | dircache_size = 0; |
878 | generate_dot_d_names(); | 932 | generate_dot_d_names(); |
@@ -909,11 +963,11 @@ int dircache_build(int last_size) | |||
909 | allocated_size = (d_names_end - buf); | 963 | allocated_size = (d_names_end - buf); |
910 | reserve_used = 0; | 964 | reserve_used = 0; |
911 | 965 | ||
912 | core_shrink(handle, dircache_root, allocated_size); | 966 | core_shrink(dircache_handle, dircache_root, allocated_size); |
913 | return res; | 967 | return res; |
914 | fail: | 968 | fail: |
915 | dircache_disable(); | 969 | dircache_disable(); |
916 | core_free(handle); | 970 | core_free(dircache_handle); |
917 | return res; | 971 | return res; |
918 | } | 972 | } |
919 | 973 | ||
@@ -928,7 +982,9 @@ void* dircache_steal_buffer(size_t *size) | |||
928 | *size = 0; | 982 | *size = 0; |
929 | return NULL; | 983 | return NULL; |
930 | } | 984 | } |
931 | 985 | ||
986 | /* since we give up the buffer (without freeing), it must not move anymore */ | ||
987 | dont_move = true; | ||
932 | *size = dircache_size + (DIRCACHE_RESERVE-reserve_used); | 988 | *size = dircache_size + (DIRCACHE_RESERVE-reserve_used); |
933 | 989 | ||
934 | return dircache_root; | 990 | return dircache_root; |
diff --git a/firmware/core_alloc.c b/firmware/core_alloc.c index 75dfc75b86..2250f5c664 100644 --- a/firmware/core_alloc.c +++ b/firmware/core_alloc.c | |||
@@ -6,7 +6,6 @@ | |||
6 | 6 | ||
7 | /* not static so it can be discovered by core_get_data() */ | 7 | /* not static so it can be discovered by core_get_data() */ |
8 | struct buflib_context core_ctx; | 8 | struct buflib_context core_ctx; |
9 | |||
10 | void core_allocator_init(void) | 9 | void core_allocator_init(void) |
11 | { | 10 | { |
12 | buffer_init(); | 11 | buffer_init(); |