Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lib/test_kho: fixes for error handling

* Update kho_test_save() so that folios array won't be freed when
returning from the function and the fdt will be freed on error
* Reset state->nr_folios to 0 in kho_test_generate_data() on error
* Simplify allocation of folios info in fdt.

Link: https://lkml.kernel.org/r/20250811082510.4154080-3-rppt@kernel.org
Fixes: b753522bed0b ("kho: add test for kexec handover")
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Reported-by: Pratyush Yadav <pratyush@kernel.org>
Closes: https://lore.kernel.org/all/mafs0zfcjcepf.fsf@kernel.org
Reviewed-by: Pratyush Yadav <pratyush@kernel.org>
Cc: Alexander Graf <graf@amazon.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: Changyuan Lyu <changyuanl@google.com>
Cc: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Thomas Weißschuh <linux@weissschuh.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Mike Rapoport (Microsoft) and committed by
Andrew Morton
950c31e8 be564840

+33 -19
+33 -19
lib/test_kho.c
··· 67 67 68 68 static int kho_test_save_data(struct kho_test_state *state, void *fdt) 69 69 { 70 - phys_addr_t *folios_info __free(kvfree) = NULL; 70 + phys_addr_t *folios_info; 71 71 int err = 0; 72 72 73 - folios_info = kvmalloc_array(state->nr_folios, sizeof(*folios_info), 74 - GFP_KERNEL); 75 - if (!folios_info) 76 - return -ENOMEM; 73 + err |= fdt_begin_node(fdt, "data"); 74 + err |= fdt_property(fdt, "nr_folios", &state->nr_folios, 75 + sizeof(state->nr_folios)); 76 + err |= fdt_property_placeholder(fdt, "folios_info", 77 + state->nr_folios * sizeof(*folios_info), 78 + (void **)&folios_info); 79 + err |= fdt_property(fdt, "csum", &state->csum, sizeof(state->csum)); 80 + err |= fdt_end_node(fdt); 81 + 82 + if (err) 83 + return err; 77 84 78 85 for (int i = 0; i < state->nr_folios; i++) { 79 86 struct folio *folio = state->folios[i]; ··· 90 83 91 84 err = kho_preserve_folio(folio); 92 85 if (err) 93 - return err; 86 + break; 94 87 } 95 - 96 - err |= fdt_begin_node(fdt, "data"); 97 - err |= fdt_property(fdt, "nr_folios", &state->nr_folios, 98 - sizeof(state->nr_folios)); 99 - err |= fdt_property(fdt, "folios_info", folios_info, 100 - state->nr_folios * sizeof(*folios_info)); 101 - err |= fdt_property(fdt, "csum", &state->csum, sizeof(state->csum)); 102 - err |= fdt_end_node(fdt); 103 88 104 89 return err; 105 90 } ··· 139 140 unsigned int size; 140 141 void *addr; 141 142 142 - /* cap allocation so that we won't exceed max_mem */ 143 + /* 144 + * Since get_order() rounds up, make sure that actual 145 + * allocation is smaller so that we won't exceed max_mem 146 + */ 143 147 if (alloc_size + (PAGE_SIZE << order) > max_mem) { 144 148 order = get_order(max_mem - alloc_size); 145 149 if (order) ··· 167 165 err_free_folios: 168 166 for (int i = 0; i < state->nr_folios; i++) 169 167 folio_put(state->folios[i]); 168 + state->nr_folios = 0; 170 169 return -ENOMEM; 171 170 } 172 171 173 172 static int kho_test_save(void) 174 173 { 175 174 struct kho_test_state *state = &kho_test_state; 176 - struct folio **folios __free(kvfree) = NULL; 175 + struct folio **folios; 177 176 unsigned long max_nr; 178 177 int err; 179 178 ··· 188 185 189 186 err = kho_test_generate_data(state); 190 187 if (err) 191 - return err; 188 + goto err_free_folios; 192 189 193 190 err = kho_test_prepare_fdt(state); 194 191 if (err) 195 - return err; 192 + goto err_free_folios; 196 193 197 - return register_kho_notifier(&kho_test_nb); 194 + err = register_kho_notifier(&kho_test_nb); 195 + if (err) 196 + goto err_free_fdt; 197 + 198 + return 0; 199 + 200 + err_free_fdt: 201 + folio_put(state->fdt); 202 + err_free_folios: 203 + kvfree(folios); 204 + return err; 198 205 } 199 206 200 207 static int kho_test_restore_data(const void *fdt, int node) ··· 304 291 folio_put(kho_test_state.folios[i]); 305 292 306 293 kvfree(kho_test_state.folios); 294 + folio_put(kho_test_state.fdt); 307 295 } 308 296 309 297 static void __exit kho_test_exit(void)