diff mbox series

[v2,bpf-next,2/2] libbpf: selftests for resizing datasec maps

Message ID 20230510223342.12886-3-inwardvessel@gmail.com (mailing list archive)
State Superseded
Delegated to: BPF
Headers show
Series libbpf: capability for resizing datasec maps | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for bpf-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 8 this patch: 8
netdev/cc_maintainers warning 13 maintainers not CCed: daniel@iogearbox.net yhs@fb.com kpsingh@kernel.org martin.lau@linux.dev john.fastabend@gmail.com song@kernel.org sdf@google.com shuah@kernel.org mykolal@fb.com linux-kselftest@vger.kernel.org jolsa@kernel.org haoluo@google.com ast@kernel.org
netdev/build_clang success Errors and warnings before: 8 this patch: 8
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 8 this patch: 8
netdev/checkpatch fail CHECK: Alignment should match open parenthesis CHECK: Lines should not end with a '(' ERROR: "fooint_last bar" should be "foo int_last bar" WARNING: Use of volatile is usually wrong: see Documentation/process/volatile-considered-harmful.rst WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? WARNING: line length of 100 exceeds 80 columns WARNING: line length of 81 exceeds 80 columns WARNING: line length of 85 exceeds 80 columns WARNING: line length of 88 exceeds 80 columns WARNING: line length of 91 exceeds 80 columns WARNING: line length of 92 exceeds 80 columns WARNING: line length of 95 exceeds 80 columns WARNING: line length of 96 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-VM_Test-10 success Logs for test_maps on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-34 success Logs for test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-36 success Logs for veristat
bpf/vmtest-bpf-next-VM_Test-11 success Logs for test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-13 success Logs for test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-16 success Logs for test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-18 success Logs for test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-21 success Logs for test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for test_progs_no_alu32_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-25 success Logs for test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-27 success Logs for test_progs_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-29 success Logs for test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-30 success Logs for test_progs_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-31 success Logs for test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-32 success Logs for test_verifier on aarch64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-35 success Logs for test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-12 success Logs for test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-14 success Logs for test_progs on aarch64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-17 success Logs for test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-19 success Logs for test_progs_no_alu32 on aarch64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-22 success Logs for test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-24 success Logs for test_progs_no_alu32_parallel on aarch64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-26 success Logs for test_progs_no_alu32_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-28 success Logs for test_progs_parallel on aarch64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-33 success Logs for test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-20 fail Logs for test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-15 fail Logs for test_progs on s390x with gcc
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-4 fail Logs for build for aarch64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-8 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-9 success Logs for veristat
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-7 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-2 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-5 success Logs for build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-3 success Logs for build for aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-6 success Logs for build for x86_64 with llvm-16

Commit Message

JP Kobryn May 10, 2023, 10:33 p.m. UTC
This patch adds test coverage for resizing datasec maps. The first two
subtests resize the bss and custom data sections. In both cases, an
initial array (of length one) has its element set to one. After resizing
the rest of the array is filled with ones as well. A BPF program is then
run to sum the respective arrays and back on the userspace side the sum
is checked to be equal to the number of elements.
The third subtest attempts to perform resizing under conditions that
will result in either the resize failing or the BTF info being dropped.

Signed-off-by: JP Kobryn <inwardvessel@gmail.com>
---
 .../bpf/prog_tests/global_map_resize.c        | 236 ++++++++++++++++++
 .../bpf/progs/test_global_map_resize.c        |  58 +++++
 2 files changed, 294 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/global_map_resize.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_global_map_resize.c

Comments

Andrii Nakryiko May 16, 2023, 9:18 p.m. UTC | #1
On Wed, May 10, 2023 at 3:33 PM JP Kobryn <inwardvessel@gmail.com> wrote:
>
> This patch adds test coverage for resizing datasec maps. The first two
> subtests resize the bss and custom data sections. In both cases, an
> initial array (of length one) has its element set to one. After resizing
> the rest of the array is filled with ones as well. A BPF program is then
> run to sum the respective arrays and back on the userspace side the sum
> is checked to be equal to the number of elements.
> The third subtest attempts to perform resizing under conditions that
> will result in either the resize failing or the BTF info being dropped.
>
> Signed-off-by: JP Kobryn <inwardvessel@gmail.com>
> ---
>  .../bpf/prog_tests/global_map_resize.c        | 236 ++++++++++++++++++
>  .../bpf/progs/test_global_map_resize.c        |  58 +++++
>  2 files changed, 294 insertions(+)
>  create mode 100644 tools/testing/selftests/bpf/prog_tests/global_map_resize.c
>  create mode 100644 tools/testing/selftests/bpf/progs/test_global_map_resize.c
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/global_map_resize.c b/tools/testing/selftests/bpf/prog_tests/global_map_resize.c
> new file mode 100644
> index 000000000000..58961789d0b3
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/prog_tests/global_map_resize.c
> @@ -0,0 +1,236 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
> +#include <errno.h>
> +#include <sys/syscall.h>
> +#include <unistd.h>
> +
> +#include "test_global_map_resize.skel.h"
> +#include "test_progs.h"
> +
> +static void run_prog_bss_array_sum(void)
> +{
> +       (void)syscall(__NR_getpid);
> +}
> +
> +static void run_prog_data_array_sum(void)
> +{
> +       (void)syscall(__NR_getuid);
> +}
> +
> +static void global_map_resize_bss_subtest(void)
> +{
> +       int err;
> +       struct test_global_map_resize *skel;
> +       struct bpf_map *map;
> +       const __u32 desired_sz = sizeof(skel->bss->sum) + (__u32)sysconf(_SC_PAGE_SIZE) * 2;
> +       size_t array_len, actual_sz;
> +
> +       skel = test_global_map_resize__open();
> +       if (!ASSERT_OK_PTR(skel, "test_global_map_resize__open"))
> +               goto teardown;
> +
> +       /* set some initial value before resizing.
> +        * it is expected this non-zero value will be preserved
> +        * while resizing.
> +        */
> +       skel->bss->array[0] = 1;
> +
> +       /* resize map value and verify the new size */
> +       map = skel->maps.bss;
> +       err = bpf_map__set_value_size(map, desired_sz);
> +       if (!ASSERT_OK(err, "bpf_map__set_value_size"))
> +               goto teardown;
> +       if (!ASSERT_EQ(bpf_map__value_size(map), desired_sz, "resize"))
> +               goto teardown;
> +
> +       /* set the expected number of elements based on the resized array */
> +       array_len = (desired_sz - sizeof(skel->bss->sum)) /
> +               (__u32)sizeof(skel->bss->array[0]);

(__u32) cast is not necessary, overly pedantic here :) same above for
desired_sz initialization


> +       if (!ASSERT_GT(array_len, 1, "array_len"))
> +               goto teardown;
> +
> +       skel->bss =
> +               (struct test_global_map_resize__bss *)bpf_map__initial_value(
> +                               skel->maps.bss, &actual_sz);

another unnecessary cast making the code ugly, please drop the casting part

> +       if (!ASSERT_OK_PTR(skel->bss, "bpf_map__initial_value (ptr)"))
> +               goto teardown;
> +       if (!ASSERT_EQ(actual_sz, desired_sz, "bpf_map__initial_value (size)"))
> +               goto teardown;
> +
> +       /* fill the newly resized array with ones,
> +        * skipping the first element which was previously set
> +        */
> +       for (int i = 1; i < array_len; i++)
> +               skel->bss->array[i] = 1;
> +
> +       /* set global const values before loading */
> +       skel->rodata->pid = getpid();
> +       skel->rodata->bss_array_len = array_len;
> +       skel->rodata->data_array_len = 1;
> +
> +       err = test_global_map_resize__load(skel);
> +       if (!ASSERT_OK(err, "test_global_map_resize__load"))
> +               goto teardown;
> +       err = test_global_map_resize__attach(skel);
> +       if (!ASSERT_OK(err, "test_global_map_resize__attach"))
> +               goto teardown;
> +
> +       /* run the bpf program which will sum the contents of the array.
> +        * since the array was filled with ones,verify the sum equals array_len
> +        */
> +       run_prog_bss_array_sum();
> +       if (!ASSERT_EQ(skel->bss->sum, array_len, "sum"))
> +               goto teardown;
> +
> +teardown:
> +       test_global_map_resize__destroy(skel);
> +}
> +
> +static void global_map_resize_data_subtest(void)
> +{
> +       int err;
> +       struct test_global_map_resize *skel;
> +       struct bpf_map *map;
> +       const __u32 desired_sz = (__u32)sysconf(_SC_PAGE_SIZE) * 2;
> +       size_t array_len, actual_sz;
> +
> +       skel = test_global_map_resize__open();
> +       if (!ASSERT_OK_PTR(skel, "test_global_map_resize__open"))
> +               goto teardown;
> +
> +       /* set some initial value before resizing.
> +        * it is expected this non-zero value will be preserved
> +        * while resizing.
> +        */
> +       skel->data_custom->my_array[0] = 1;
> +
> +       /* resize map value and verify the new size */
> +       map = skel->maps.data_custom;
> +       err = bpf_map__set_value_size(map, desired_sz);
> +       if (!ASSERT_OK(err, "bpf_map__set_value_size"))
> +               goto teardown;
> +       if (!ASSERT_EQ(bpf_map__value_size(map), desired_sz, "resize"))
> +               goto teardown;
> +
> +       /* set the expected number of elements based on the resized array */
> +       array_len = (desired_sz - sizeof(skel->bss->sum)) /
> +               (__u32)sizeof(skel->data_custom->my_array[0]);
> +       if (!ASSERT_GT(array_len, 1, "array_len"))
> +               goto teardown;
> +
> +       skel->data_custom =
> +               (struct test_global_map_resize__data_custom *)bpf_map__initial_value(
> +                               skel->maps.data_custom, &actual_sz);

all the same points about pedantic and unnecessary casts, please simplify

> +       if (!ASSERT_OK_PTR(skel->data_custom, "bpf_map__initial_value (ptr)"))
> +               goto teardown;
> +       if (!ASSERT_EQ(actual_sz, desired_sz, "bpf_map__initial_value (size)"))
> +               goto teardown;
> +
> +       /* fill the newly resized array with ones,
> +        * skipping the first element which was previously set
> +        */
> +       for (int i = 1; i < array_len; i++)
> +               skel->data_custom->my_array[i] = 1;
> +
> +       /* set global const values before loading */
> +       skel->rodata->pid = getpid();
> +       skel->rodata->bss_array_len = 1;
> +       skel->rodata->data_array_len = array_len;
> +
> +       err = test_global_map_resize__load(skel);
> +       if (!ASSERT_OK(err, "test_global_map_resize__load"))
> +               goto teardown;
> +       err = test_global_map_resize__attach(skel);
> +       if (!ASSERT_OK(err, "test_global_map_resize__attach"))
> +               goto teardown;
> +
> +       /* run the bpf program which will sum the contents of the array.
> +        * since the array was filled with ones,verify the sum equals array_len
> +        */
> +       run_prog_data_array_sum();
> +       if (!ASSERT_EQ(skel->bss->sum, array_len, "sum"))
> +               goto teardown;
> +
> +teardown:
> +       test_global_map_resize__destroy(skel);
> +}
> +
> +static void global_map_resize_invalid_subtest(void)
> +{
> +       int err;
> +       struct test_global_map_resize *skel;
> +       struct bpf_map *map;
> +       __u32 element_sz, desired_sz;
> +
> +       skel = test_global_map_resize__open();
> +       if (!ASSERT_OK_PTR(skel, "test_global_map_resize__open"))
> +               return;
> +
> +        /* attempt to resize a global datasec map to size
> +         * which does NOT align with array
> +         */

indentation seems off, please double check

> +       map = skel->maps.data_custom;
> +       if (!ASSERT_NEQ(bpf_map__btf_value_type_id(map), 0, ".data.custom initial btf"))
> +               goto teardown;
> +       /* set desired size a fraction of element size beyond an aligned size */
> +       element_sz = (__u32)sizeof(skel->data_custom->my_array[0]);
> +       desired_sz = element_sz + element_sz / 2;
> +       /* confirm desired size does NOT align with array */
> +       if (!ASSERT_NEQ(desired_sz % element_sz, 0, "my_array alignment"))
> +               goto teardown;
> +       err = bpf_map__set_value_size(map, desired_sz);
> +       /* confirm resize is OK but BTF info is dropped */
> +       if (!ASSERT_OK(err, ".data.custom bpf_map__set_value_size") ||
> +               !ASSERT_EQ(bpf_map__btf_key_type_id(map), 0, ".data.custom drop btf key") ||
> +               !ASSERT_EQ(bpf_map__btf_value_type_id(map), 0, ".data.custom drop btf val"))
> +               goto teardown;
> +
> +       /* attempt to resize a global datasec map
> +        * whose only var is NOT an array
> +        */
> +       map = skel->maps.data_non_array;
> +       if (!ASSERT_NEQ(bpf_map__btf_value_type_id(map), 0, ".data.non_array initial btf"))
> +               goto teardown;
> +       /* set desired size to arbitrary value */
> +       desired_sz = 1024;
> +       err = bpf_map__set_value_size(map, desired_sz);
> +       /* confirm resize is OK but BTF info is dropped */
> +       if (!ASSERT_OK(err, ".data.non_array bpf_map__set_value_size") ||
> +               !ASSERT_EQ(bpf_map__btf_key_type_id(map), 0, ".data.non_array drop btf key") ||
> +               !ASSERT_EQ(bpf_map__btf_value_type_id(map), 0, ".data.non_array drop btf val"))
> +               goto teardown;
> +
> +       /* attempt to resize a global datasec map
> +        * whose last var is NOT an array
> +        */
> +       map = skel->maps.data_array_not_last;
> +       if (!ASSERT_NEQ(bpf_map__btf_value_type_id(map), 0, ".data.array_not_last initial btf"))
> +               goto teardown;
> +       /* set desired size to a multiple of element size */
> +       element_sz = (__u32)sizeof(skel->data_array_not_last->my_array_first[0]);
> +       desired_sz = element_sz * 8;
> +       /* confirm desired size aligns with array */
> +       if (!ASSERT_EQ(desired_sz % element_sz, 0, "my_array_first alignment"))
> +               goto teardown;
> +       err = bpf_map__set_value_size(map, desired_sz);
> +       /* confirm resize is OK but BTF info is dropped */
> +       if (!ASSERT_OK(err, ".data.array_not_last bpf_map__set_value_size") ||
> +               !ASSERT_EQ(bpf_map__btf_key_type_id(map), 0, ".data.array_not_last drop btf key") ||
> +               !ASSERT_EQ(bpf_map__btf_value_type_id(map), 0, ".data.array_not_last drop btf val"))
> +               goto teardown;
> +
> +teardown:
> +       test_global_map_resize__destroy(skel);
> +}
> +
> +void test_global_map_resize(void)
> +{
> +       if (test__start_subtest("global_map_resize_bss"))
> +               global_map_resize_bss_subtest();
> +
> +       if (test__start_subtest("global_map_resize_data"))
> +               global_map_resize_data_subtest();
> +
> +       if (test__start_subtest("global_map_resize_invalid"))
> +               global_map_resize_invalid_subtest();
> +}
> diff --git a/tools/testing/selftests/bpf/progs/test_global_map_resize.c b/tools/testing/selftests/bpf/progs/test_global_map_resize.c
> new file mode 100644
> index 000000000000..2588f2384246
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/progs/test_global_map_resize.c
> @@ -0,0 +1,58 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
> +
> +#include "vmlinux.h"
> +#include <bpf/bpf_helpers.h>
> +
> +char _license[] SEC("license") = "GPL";
> +
> +/* rodata section */
> +const volatile pid_t pid;
> +const volatile size_t bss_array_len;
> +const volatile size_t data_array_len;
> +
> +/* bss section */
> +int sum = 0;
> +int array[1];
> +
> +/* custom data secton */

typo: section

> +int my_array[1] SEC(".data.custom");
> +
> +/* custom data section which should NOT be resizable,
> + * since it contains a single var which is not an array
> + */
> +int my_int SEC(".data.non_array");
> +
> +/* custom data section which should NOT be resizable,
> + * since its last var is not an array
> + */
> +int my_array_first[1] SEC(".data.array_not_last");
> +int my_int_last SEC(".data.array_not_last");
> +
> +SEC("tp/syscalls/sys_enter_getpid")
> +int bss_array_sum(void *ctx)
> +{
> +       if (pid != (bpf_get_current_pid_tgid() >> 32))
> +               return 0;
> +
> +       sum = 0;
> +
> +       for (size_t i = 0; i < bss_array_len; ++i)
> +               sum += array[i];
> +
> +       return 0;
> +}
> +
> +SEC("tp/syscalls/sys_enter_getuid")
> +int data_array_sum(void *ctx)
> +{
> +       if (pid != (bpf_get_current_pid_tgid() >> 32))
> +               return 0;
> +
> +       sum = 0;
> +
> +       for (size_t i = 0; i < data_array_len; ++i)
> +               sum += my_array[i];
> +
> +       return 0;
> +}
> --
> 2.40.0
>
diff mbox series

Patch

diff --git a/tools/testing/selftests/bpf/prog_tests/global_map_resize.c b/tools/testing/selftests/bpf/prog_tests/global_map_resize.c
new file mode 100644
index 000000000000..58961789d0b3
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/global_map_resize.c
@@ -0,0 +1,236 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
+#include <errno.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "test_global_map_resize.skel.h"
+#include "test_progs.h"
+
+static void run_prog_bss_array_sum(void)
+{
+	(void)syscall(__NR_getpid);
+}
+
+static void run_prog_data_array_sum(void)
+{
+	(void)syscall(__NR_getuid);
+}
+
+static void global_map_resize_bss_subtest(void)
+{
+	int err;
+	struct test_global_map_resize *skel;
+	struct bpf_map *map;
+	const __u32 desired_sz = sizeof(skel->bss->sum) + (__u32)sysconf(_SC_PAGE_SIZE) * 2;
+	size_t array_len, actual_sz;
+
+	skel = test_global_map_resize__open();
+	if (!ASSERT_OK_PTR(skel, "test_global_map_resize__open"))
+		goto teardown;
+
+	/* set some initial value before resizing.
+	 * it is expected this non-zero value will be preserved
+	 * while resizing.
+	 */
+	skel->bss->array[0] = 1;
+
+	/* resize map value and verify the new size */
+	map = skel->maps.bss;
+	err = bpf_map__set_value_size(map, desired_sz);
+	if (!ASSERT_OK(err, "bpf_map__set_value_size"))
+		goto teardown;
+	if (!ASSERT_EQ(bpf_map__value_size(map), desired_sz, "resize"))
+		goto teardown;
+
+	/* set the expected number of elements based on the resized array */
+	array_len = (desired_sz - sizeof(skel->bss->sum)) /
+		(__u32)sizeof(skel->bss->array[0]);
+	if (!ASSERT_GT(array_len, 1, "array_len"))
+		goto teardown;
+
+	skel->bss =
+		(struct test_global_map_resize__bss *)bpf_map__initial_value(
+				skel->maps.bss, &actual_sz);
+	if (!ASSERT_OK_PTR(skel->bss, "bpf_map__initial_value (ptr)"))
+		goto teardown;
+	if (!ASSERT_EQ(actual_sz, desired_sz, "bpf_map__initial_value (size)"))
+		goto teardown;
+
+	/* fill the newly resized array with ones,
+	 * skipping the first element which was previously set
+	 */
+	for (int i = 1; i < array_len; i++)
+		skel->bss->array[i] = 1;
+
+	/* set global const values before loading */
+	skel->rodata->pid = getpid();
+	skel->rodata->bss_array_len = array_len;
+	skel->rodata->data_array_len = 1;
+
+	err = test_global_map_resize__load(skel);
+	if (!ASSERT_OK(err, "test_global_map_resize__load"))
+		goto teardown;
+	err = test_global_map_resize__attach(skel);
+	if (!ASSERT_OK(err, "test_global_map_resize__attach"))
+		goto teardown;
+
+	/* run the bpf program which will sum the contents of the array.
+	 * since the array was filled with ones,verify the sum equals array_len
+	 */
+	run_prog_bss_array_sum();
+	if (!ASSERT_EQ(skel->bss->sum, array_len, "sum"))
+		goto teardown;
+
+teardown:
+	test_global_map_resize__destroy(skel);
+}
+
+static void global_map_resize_data_subtest(void)
+{
+	int err;
+	struct test_global_map_resize *skel;
+	struct bpf_map *map;
+	const __u32 desired_sz = (__u32)sysconf(_SC_PAGE_SIZE) * 2;
+	size_t array_len, actual_sz;
+
+	skel = test_global_map_resize__open();
+	if (!ASSERT_OK_PTR(skel, "test_global_map_resize__open"))
+		goto teardown;
+
+	/* set some initial value before resizing.
+	 * it is expected this non-zero value will be preserved
+	 * while resizing.
+	 */
+	skel->data_custom->my_array[0] = 1;
+
+	/* resize map value and verify the new size */
+	map = skel->maps.data_custom;
+	err = bpf_map__set_value_size(map, desired_sz);
+	if (!ASSERT_OK(err, "bpf_map__set_value_size"))
+		goto teardown;
+	if (!ASSERT_EQ(bpf_map__value_size(map), desired_sz, "resize"))
+		goto teardown;
+
+	/* set the expected number of elements based on the resized array */
+	array_len = (desired_sz - sizeof(skel->bss->sum)) /
+		(__u32)sizeof(skel->data_custom->my_array[0]);
+	if (!ASSERT_GT(array_len, 1, "array_len"))
+		goto teardown;
+
+	skel->data_custom =
+		(struct test_global_map_resize__data_custom *)bpf_map__initial_value(
+				skel->maps.data_custom, &actual_sz);
+	if (!ASSERT_OK_PTR(skel->data_custom, "bpf_map__initial_value (ptr)"))
+		goto teardown;
+	if (!ASSERT_EQ(actual_sz, desired_sz, "bpf_map__initial_value (size)"))
+		goto teardown;
+
+	/* fill the newly resized array with ones,
+	 * skipping the first element which was previously set
+	 */
+	for (int i = 1; i < array_len; i++)
+		skel->data_custom->my_array[i] = 1;
+
+	/* set global const values before loading */
+	skel->rodata->pid = getpid();
+	skel->rodata->bss_array_len = 1;
+	skel->rodata->data_array_len = array_len;
+
+	err = test_global_map_resize__load(skel);
+	if (!ASSERT_OK(err, "test_global_map_resize__load"))
+		goto teardown;
+	err = test_global_map_resize__attach(skel);
+	if (!ASSERT_OK(err, "test_global_map_resize__attach"))
+		goto teardown;
+
+	/* run the bpf program which will sum the contents of the array.
+	 * since the array was filled with ones,verify the sum equals array_len
+	 */
+	run_prog_data_array_sum();
+	if (!ASSERT_EQ(skel->bss->sum, array_len, "sum"))
+		goto teardown;
+
+teardown:
+	test_global_map_resize__destroy(skel);
+}
+
+static void global_map_resize_invalid_subtest(void)
+{
+	int err;
+	struct test_global_map_resize *skel;
+	struct bpf_map *map;
+	__u32 element_sz, desired_sz;
+
+	skel = test_global_map_resize__open();
+	if (!ASSERT_OK_PTR(skel, "test_global_map_resize__open"))
+		return;
+
+	 /* attempt to resize a global datasec map to size
+	  * which does NOT align with array
+	  */
+	map = skel->maps.data_custom;
+	if (!ASSERT_NEQ(bpf_map__btf_value_type_id(map), 0, ".data.custom initial btf"))
+		goto teardown;
+	/* set desired size a fraction of element size beyond an aligned size */
+	element_sz = (__u32)sizeof(skel->data_custom->my_array[0]);
+	desired_sz = element_sz + element_sz / 2;
+	/* confirm desired size does NOT align with array */
+	if (!ASSERT_NEQ(desired_sz % element_sz, 0, "my_array alignment"))
+		goto teardown;
+	err = bpf_map__set_value_size(map, desired_sz);
+	/* confirm resize is OK but BTF info is dropped */
+	if (!ASSERT_OK(err, ".data.custom bpf_map__set_value_size") ||
+		!ASSERT_EQ(bpf_map__btf_key_type_id(map), 0, ".data.custom drop btf key") ||
+		!ASSERT_EQ(bpf_map__btf_value_type_id(map), 0, ".data.custom drop btf val"))
+		goto teardown;
+
+	/* attempt to resize a global datasec map
+	 * whose only var is NOT an array
+	 */
+	map = skel->maps.data_non_array;
+	if (!ASSERT_NEQ(bpf_map__btf_value_type_id(map), 0, ".data.non_array initial btf"))
+		goto teardown;
+	/* set desired size to arbitrary value */
+	desired_sz = 1024;
+	err = bpf_map__set_value_size(map, desired_sz);
+	/* confirm resize is OK but BTF info is dropped */
+	if (!ASSERT_OK(err, ".data.non_array bpf_map__set_value_size") ||
+		!ASSERT_EQ(bpf_map__btf_key_type_id(map), 0, ".data.non_array drop btf key") ||
+		!ASSERT_EQ(bpf_map__btf_value_type_id(map), 0, ".data.non_array drop btf val"))
+		goto teardown;
+
+	/* attempt to resize a global datasec map
+	 * whose last var is NOT an array
+	 */
+	map = skel->maps.data_array_not_last;
+	if (!ASSERT_NEQ(bpf_map__btf_value_type_id(map), 0, ".data.array_not_last initial btf"))
+		goto teardown;
+	/* set desired size to a multiple of element size */
+	element_sz = (__u32)sizeof(skel->data_array_not_last->my_array_first[0]);
+	desired_sz = element_sz * 8;
+	/* confirm desired size aligns with array */
+	if (!ASSERT_EQ(desired_sz % element_sz, 0, "my_array_first alignment"))
+		goto teardown;
+	err = bpf_map__set_value_size(map, desired_sz);
+	/* confirm resize is OK but BTF info is dropped */
+	if (!ASSERT_OK(err, ".data.array_not_last bpf_map__set_value_size") ||
+		!ASSERT_EQ(bpf_map__btf_key_type_id(map), 0, ".data.array_not_last drop btf key") ||
+		!ASSERT_EQ(bpf_map__btf_value_type_id(map), 0, ".data.array_not_last drop btf val"))
+		goto teardown;
+
+teardown:
+	test_global_map_resize__destroy(skel);
+}
+
+void test_global_map_resize(void)
+{
+	if (test__start_subtest("global_map_resize_bss"))
+		global_map_resize_bss_subtest();
+
+	if (test__start_subtest("global_map_resize_data"))
+		global_map_resize_data_subtest();
+
+	if (test__start_subtest("global_map_resize_invalid"))
+		global_map_resize_invalid_subtest();
+}
diff --git a/tools/testing/selftests/bpf/progs/test_global_map_resize.c b/tools/testing/selftests/bpf/progs/test_global_map_resize.c
new file mode 100644
index 000000000000..2588f2384246
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_global_map_resize.c
@@ -0,0 +1,58 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+
+char _license[] SEC("license") = "GPL";
+
+/* rodata section */
+const volatile pid_t pid;
+const volatile size_t bss_array_len;
+const volatile size_t data_array_len;
+
+/* bss section */
+int sum = 0;
+int array[1];
+
+/* custom data secton */
+int my_array[1] SEC(".data.custom");
+
+/* custom data section which should NOT be resizable,
+ * since it contains a single var which is not an array
+ */
+int my_int SEC(".data.non_array");
+
+/* custom data section which should NOT be resizable,
+ * since its last var is not an array
+ */
+int my_array_first[1] SEC(".data.array_not_last");
+int my_int_last SEC(".data.array_not_last");
+
+SEC("tp/syscalls/sys_enter_getpid")
+int bss_array_sum(void *ctx)
+{
+	if (pid != (bpf_get_current_pid_tgid() >> 32))
+		return 0;
+
+	sum = 0;
+
+	for (size_t i = 0; i < bss_array_len; ++i)
+		sum += array[i];
+
+	return 0;
+}
+
+SEC("tp/syscalls/sys_enter_getuid")
+int data_array_sum(void *ctx)
+{
+	if (pid != (bpf_get_current_pid_tgid() >> 32))
+		return 0;
+
+	sum = 0;
+
+	for (size_t i = 0; i < data_array_len; ++i)
+		sum += my_array[i];
+
+	return 0;
+}