mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 10:01:39 -05:00
test_kho: unpreserve memory in case of error
If there is an error half way through KHO memory preservation, we should rollback and unpreserve everything that is partially preserved. Link: https://lkml.kernel.org/r/20251101142325.1326536-6-pasha.tatashin@soleen.com Co-developed-by: Mike Rapoport (Microsoft) <rppt@kernel.org> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com> Cc: Alexander Graf <graf@amazon.com> Cc: Changyuan Lyu <changyuanl@google.com> Cc: Christian Brauner <brauner@kernel.org> Cc: Jason Gunthorpe <jgg@nvidia.com> Cc: Jason Gunthorpe <jgg@ziepe.ca> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Masahiro Yamada <masahiroy@kernel.org> Cc: Miguel Ojeda <ojeda@kernel.org> Cc: Pratyush Yadav <pratyush@kernel.org> Cc: Randy Dunlap <rdunlap@infradead.org> Cc: Simon Horman <horms@kernel.org> Cc: Tejun Heo <tj@kernel.org> Cc: Zhu Yanjun <yanjun.zhu@linux.dev> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
committed by
Andrew Morton
parent
f5bfd4793a
commit
ce405ed510
103
lib/test_kho.c
103
lib/test_kho.c
@@ -33,17 +33,28 @@ struct kho_test_state {
|
||||
unsigned int nr_folios;
|
||||
struct folio **folios;
|
||||
phys_addr_t *folios_info;
|
||||
struct kho_vmalloc folios_info_phys;
|
||||
int nr_folios_preserved;
|
||||
struct folio *fdt;
|
||||
__wsum csum;
|
||||
};
|
||||
|
||||
static struct kho_test_state kho_test_state;
|
||||
|
||||
static int kho_test_save_data(struct kho_test_state *state, void *fdt)
|
||||
static void kho_test_unpreserve_data(struct kho_test_state *state)
|
||||
{
|
||||
for (int i = 0; i < state->nr_folios_preserved; i++)
|
||||
kho_unpreserve_folio(state->folios[i]);
|
||||
|
||||
kho_unpreserve_vmalloc(&state->folios_info_phys);
|
||||
vfree(state->folios_info);
|
||||
}
|
||||
|
||||
static int kho_test_preserve_data(struct kho_test_state *state)
|
||||
{
|
||||
phys_addr_t *folios_info __free(kvfree) = NULL;
|
||||
struct kho_vmalloc folios_info_phys;
|
||||
int err = 0;
|
||||
phys_addr_t *folios_info;
|
||||
int err;
|
||||
|
||||
folios_info = vmalloc_array(state->nr_folios, sizeof(*folios_info));
|
||||
if (!folios_info)
|
||||
@@ -51,64 +62,98 @@ static int kho_test_save_data(struct kho_test_state *state, void *fdt)
|
||||
|
||||
err = kho_preserve_vmalloc(folios_info, &folios_info_phys);
|
||||
if (err)
|
||||
return err;
|
||||
goto err_free_info;
|
||||
|
||||
state->folios_info_phys = folios_info_phys;
|
||||
state->folios_info = folios_info;
|
||||
|
||||
for (int i = 0; i < state->nr_folios; i++) {
|
||||
struct folio *folio = state->folios[i];
|
||||
unsigned int order = folio_order(folio);
|
||||
|
||||
folios_info[i] = virt_to_phys(folio_address(folio)) | order;
|
||||
|
||||
err = kho_preserve_folio(folio);
|
||||
if (err)
|
||||
break;
|
||||
goto err_unpreserve;
|
||||
state->nr_folios_preserved++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unpreserve:
|
||||
/*
|
||||
* kho_test_unpreserve_data frees folio_info, bail out immediately to
|
||||
* avoid double free
|
||||
*/
|
||||
kho_test_unpreserve_data(state);
|
||||
return err;
|
||||
|
||||
err_free_info:
|
||||
vfree(folios_info);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int kho_test_prepare_fdt(struct kho_test_state *state, ssize_t fdt_size)
|
||||
{
|
||||
const char compatible[] = KHO_TEST_COMPAT;
|
||||
unsigned int magic = KHO_TEST_MAGIC;
|
||||
void *fdt = folio_address(state->fdt);
|
||||
int err;
|
||||
|
||||
err = fdt_create(fdt, fdt_size);
|
||||
err |= fdt_finish_reservemap(fdt);
|
||||
err |= fdt_begin_node(fdt, "");
|
||||
err |= fdt_property(fdt, "compatible", compatible, sizeof(compatible));
|
||||
err |= fdt_property(fdt, "magic", &magic, sizeof(magic));
|
||||
|
||||
err |= fdt_begin_node(fdt, "data");
|
||||
err |= fdt_property(fdt, "nr_folios", &state->nr_folios,
|
||||
sizeof(state->nr_folios));
|
||||
err |= fdt_property(fdt, "folios_info", &folios_info_phys,
|
||||
sizeof(folios_info_phys));
|
||||
err |= fdt_property(fdt, "folios_info", &state->folios_info_phys,
|
||||
sizeof(state->folios_info_phys));
|
||||
err |= fdt_property(fdt, "csum", &state->csum, sizeof(state->csum));
|
||||
err |= fdt_end_node(fdt);
|
||||
|
||||
if (!err)
|
||||
state->folios_info = no_free_ptr(folios_info);
|
||||
err |= fdt_end_node(fdt);
|
||||
err |= fdt_finish(fdt);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int kho_test_prepare_fdt(struct kho_test_state *state)
|
||||
static int kho_test_preserve(struct kho_test_state *state)
|
||||
{
|
||||
const char compatible[] = KHO_TEST_COMPAT;
|
||||
unsigned int magic = KHO_TEST_MAGIC;
|
||||
ssize_t fdt_size;
|
||||
int err = 0;
|
||||
void *fdt;
|
||||
int err;
|
||||
|
||||
fdt_size = state->nr_folios * sizeof(phys_addr_t) + PAGE_SIZE;
|
||||
state->fdt = folio_alloc(GFP_KERNEL, get_order(fdt_size));
|
||||
if (!state->fdt)
|
||||
return -ENOMEM;
|
||||
|
||||
fdt = folio_address(state->fdt);
|
||||
err = kho_preserve_folio(state->fdt);
|
||||
if (err)
|
||||
goto err_free_fdt;
|
||||
|
||||
err |= kho_preserve_folio(state->fdt);
|
||||
err |= fdt_create(fdt, fdt_size);
|
||||
err |= fdt_finish_reservemap(fdt);
|
||||
err = kho_test_preserve_data(state);
|
||||
if (err)
|
||||
goto err_unpreserve_fdt;
|
||||
|
||||
err |= fdt_begin_node(fdt, "");
|
||||
err |= fdt_property(fdt, "compatible", compatible, sizeof(compatible));
|
||||
err |= fdt_property(fdt, "magic", &magic, sizeof(magic));
|
||||
err |= kho_test_save_data(state, fdt);
|
||||
err |= fdt_end_node(fdt);
|
||||
|
||||
err |= fdt_finish(fdt);
|
||||
err = kho_test_prepare_fdt(state, fdt_size);
|
||||
if (err)
|
||||
goto err_unpreserve_data;
|
||||
|
||||
err = kho_add_subtree(KHO_TEST_FDT, folio_address(state->fdt));
|
||||
if (err)
|
||||
folio_put(state->fdt);
|
||||
goto err_unpreserve_data;
|
||||
|
||||
return 0;
|
||||
|
||||
err_unpreserve_data:
|
||||
kho_test_unpreserve_data(state);
|
||||
err_unpreserve_fdt:
|
||||
kho_unpreserve_folio(state->fdt);
|
||||
err_free_fdt:
|
||||
folio_put(state->fdt);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -174,14 +219,12 @@ static int kho_test_save(void)
|
||||
if (err)
|
||||
goto err_free_folios;
|
||||
|
||||
err = kho_test_prepare_fdt(state);
|
||||
err = kho_test_preserve(state);
|
||||
if (err)
|
||||
goto err_free_folios;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_fdt:
|
||||
folio_put(state->fdt);
|
||||
err_free_folios:
|
||||
kvfree(folios);
|
||||
return err;
|
||||
|
||||
Reference in New Issue
Block a user