diff mbox series

[bpf-next,v2] bpftool: Mount bpffs on provided dir instead of parent dir

Message ID 20240308130619.28123-1-icegambit91@gmail.com (mailing list archive)
State Superseded
Delegated to: BPF
Headers show
Series [bpf-next,v2] bpftool: Mount bpffs on provided dir instead of parent dir | expand

Checks

Context Check Description
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for bpf-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
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/build_tools success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers fail 1 blamed authors not CCed: yangpc@wangsu.com; 1 maintainers not CCed: yangpc@wangsu.com
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 fail Problems with Fixes tag: 1
netdev/build_allmodconfig_warn success Errors and warnings before: 8 this patch: 8
netdev/checkpatch warning WARNING: Prefer strscpy over strcpy - see: https://github.com/KSPP/linux/issues/88 WARNING: line length of 90 exceeds 80 columns WARNING: line length of 94 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-PR fail PR summary
bpf/vmtest-bpf-next-VM_Test-0 success Logs for Lint
bpf/vmtest-bpf-next-VM_Test-2 success Logs for Unittests
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-3 success Logs for Validate matrix.py
bpf/vmtest-bpf-next-VM_Test-5 success Logs for aarch64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-4 success Logs for aarch64-gcc / build / build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for aarch64-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-12 success Logs for s390x-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-9 success Logs for aarch64-gcc / test (test_verifier, false, 360) / test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-11 success Logs for s390x-gcc / build / build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-17 success Logs for s390x-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-20 success Logs for x86_64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-18 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-19 success Logs for x86_64-gcc / build / build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-28 success Logs for x86_64-llvm-17 / build / build for x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-34 success Logs for x86_64-llvm-17 / veristat
bpf/vmtest-bpf-next-VM_Test-6 success Logs for aarch64-gcc / test (test_maps, false, 360) / test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-7 success Logs for aarch64-gcc / test (test_progs, false, 360) / test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-35 success Logs for x86_64-llvm-18 / build / build for x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-42 success Logs for x86_64-llvm-18 / veristat
bpf/vmtest-bpf-next-VM_Test-8 success Logs for aarch64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-16 success Logs for s390x-gcc / test (test_verifier, false, 360) / test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-15 fail Logs for s390x-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-13 success Logs for s390x-gcc / test (test_maps, false, 360) / test_maps on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-36 success Logs for x86_64-llvm-18 / build-release / build for x86_64 with llvm-18 and -O2 optimization
bpf/vmtest-bpf-next-VM_Test-14 fail Logs for s390x-gcc / test (test_progs, false, 360) / test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-21 success Logs for x86_64-gcc / test (test_maps, false, 360) / test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 success Logs for x86_64-gcc / test (test_progs, false, 360) / test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for x86_64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-26 success Logs for x86_64-gcc / test (test_verifier, false, 360) / test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-25 success Logs for x86_64-gcc / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-27 success Logs for x86_64-gcc / veristat / veristat on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for x86_64-gcc / test (test_progs_no_alu32_parallel, true, 30) / test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-30 success Logs for x86_64-llvm-17 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-32 success Logs for x86_64-llvm-17 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-41 success Logs for x86_64-llvm-18 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-33 success Logs for x86_64-llvm-17 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-29 success Logs for x86_64-llvm-17 / build-release / build for x86_64 with llvm-17 and -O2 optimization
bpf/vmtest-bpf-next-VM_Test-31 success Logs for x86_64-llvm-17 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-37 success Logs for x86_64-llvm-18 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-38 success Logs for x86_64-llvm-18 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-39 success Logs for x86_64-llvm-18 / test (test_progs_cpuv4, false, 360) / test_progs_cpuv4 on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-40 success Logs for x86_64-llvm-18 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-18

Commit Message

Sahil Siddiq March 8, 2024, 1:06 p.m. UTC
When pinning programs/objects under PATH (eg: during "bpftool prog
loadall") the bpffs is mounted on the parent dir of PATH in the
following situations:
- the given dir exists but it is not bpffs.
- the given dir doesn't exist and the parent dir is not bpffs.

Mounting on the parent dir can also have the unintentional side-
effect of hiding other files located under the parent dir.

If the given dir exists but is not bpffs, then the bpffs should
be mounted on the given dir and not its parent dir.

Similarly, if the given dir doesn't exist and its parent dir is not
bpffs, then the given dir should be created and the bpffs should be
mounted on this new dir.

Link: https://lore.kernel.org/bpf/2da44d24-74ae-a564-1764-afccf395eeec@isovalent.com/T/#t

Closes: https://github.com/libbpf/bpftool/issues/100

Fixes: 2a36c26fe3b8 ("bpftool: Support bpffs mountpoint as pin path for prog loadall")

Signed-off-by: Sahil Siddiq <icegambit91@gmail.com>
---
Changes since v1:
 - Split "mount_bpffs_for_pin" into two functions:
   - mount_bpffs_on_dir
   - mount_bpffs_given_file
   This is done to improve maintainability and readability.
 - Improve error messages
 - (mount_bpffs_given_file): If the file already exists, throw an
   error instead of waiting for bpf_obj_pin() to throw an error
 - Code style changes

 tools/bpf/bpftool/common.c     | 78 +++++++++++++++++++++++++++++-----
 tools/bpf/bpftool/iter.c       |  2 +-
 tools/bpf/bpftool/main.h       |  3 +-
 tools/bpf/bpftool/prog.c       |  5 ++-
 tools/bpf/bpftool/struct_ops.c |  2 +-
 5 files changed, 75 insertions(+), 15 deletions(-)

Comments

Quentin Monnet March 13, 2024, 3:47 p.m. UTC | #1
Thanks! Apologies for the delay.

2024-03-08 13:07 UTC+0000 ~ Sahil Siddiq <icegambit91@gmail.com>
> When pinning programs/objects under PATH (eg: during "bpftool prog
> loadall") the bpffs is mounted on the parent dir of PATH in the
> following situations:
> - the given dir exists but it is not bpffs.
> - the given dir doesn't exist and the parent dir is not bpffs.
> 
> Mounting on the parent dir can also have the unintentional side-
> effect of hiding other files located under the parent dir.
> 
> If the given dir exists but is not bpffs, then the bpffs should
> be mounted on the given dir and not its parent dir.
> 
> Similarly, if the given dir doesn't exist and its parent dir is not
> bpffs, then the given dir should be created and the bpffs should be
> mounted on this new dir.
> 
> Link: https://lore.kernel.org/bpf/2da44d24-74ae-a564-1764-afccf395eeec@isovalent.com/T/#t
> 
> Closes: https://github.com/libbpf/bpftool/issues/100
> 
> Fixes: 2a36c26fe3b8 ("bpftool: Support bpffs mountpoint as pin path for prog loadall")
> 
> Signed-off-by: Sahil Siddiq <icegambit91@gmail.com>

Note: you don't need the blank lines between the tags.

> ---
> Changes since v1:
>  - Split "mount_bpffs_for_pin" into two functions:
>    - mount_bpffs_on_dir
>    - mount_bpffs_given_file
>    This is done to improve maintainability and readability.
>  - Improve error messages
>  - (mount_bpffs_given_file): If the file already exists, throw an
>    error instead of waiting for bpf_obj_pin() to throw an error
>  - Code style changes

You can keep the changelog as part of the patch description.

> 
>  tools/bpf/bpftool/common.c     | 78 +++++++++++++++++++++++++++++-----
>  tools/bpf/bpftool/iter.c       |  2 +-
>  tools/bpf/bpftool/main.h       |  3 +-
>  tools/bpf/bpftool/prog.c       |  5 ++-
>  tools/bpf/bpftool/struct_ops.c |  2 +-
>  5 files changed, 75 insertions(+), 15 deletions(-)
> 
> diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
> index cc6e6aae2447..d2746681200e 100644
> --- a/tools/bpf/bpftool/common.c
> +++ b/tools/bpf/bpftool/common.c
> @@ -244,24 +244,80 @@ int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type)
>  	return fd;
>  }
>  
> -int mount_bpffs_for_pin(const char *name, bool is_dir)
> +int mount_bpffs_on_dir(const char *dir_name)

With all the checks and the potential directory creation, we could maybe
rename this into "prepare_bpffs_dir()" or something like this?

>  {
>  	char err_str[ERR_MAX_LEN];
> -	char *file;
> -	char *dir;
>  	int err = 0;
>  
> -	if (is_dir && is_bpffs(name))
> +	if (is_bpffs(dir_name))
>  		return err;
>  
> -	file = malloc(strlen(name) + 1);
> -	if (!file) {
> +	if (access(dir_name, F_OK) == -1) {
> +		char *temp_name;
> +		char *parent_name;
> +
> +		temp_name = malloc(strlen(dir_name) + 1);
> +		if (!temp_name) {
> +			p_err("mem alloc failed");
> +			return -1;
> +		}
> +
> +		strcpy(temp_name, dir_name);
> +		parent_name = dirname(temp_name);
> +
> +		if (is_bpffs(parent_name)) {
> +			/* nothing to do if already mounted */
> +			free(temp_name);
> +			return err;
> +		}
> +
> +		free(temp_name);
> +
> +		if (block_mount) {
> +			p_err("no BPF file system found, not mounting it due to --nomount option");
> +			return -1;
> +		}
> +
> +		err = mkdir(dir_name, 0700);
> +		if (err) {
> +			p_err("failed to create dir (%s): %s", dir_name, strerror(errno));
> +			return err;
> +		}
> +	} else if (block_mount) {
> +		p_err("no BPF file system found, not mounting it due to --nomount option");
> +		return -1;
> +	}

I'd maybe change this block a little (although it's up to you):

	bool dir_exists;

	dire_exists = (access(...) == 0);
	if (!dir_exists) {
		...
		free(temp_name);
	}

	if (block_mount) {
		...
	}

	if (!dir_exists) {
		err = mkdir(...);
		...
	}

	err = mnt_fs(...);
	...

This would also enable us to remove the directory we just created, if
we're not able to mount the bpffs on it, before leaving the function.

> +
> +	err = mnt_fs(dir_name, "bpf", err_str, ERR_MAX_LEN);
> +	if (err) {
> +		err_str[ERR_MAX_LEN - 1] = '\0';
> +		p_err("can't mount BPF file system on given dir (%s): %s",
> +		      dir_name, err_str);
> +	}
> +
> +	return err;
> +}
> +
> +int mount_bpffs_given_file(const char *file_name)

I'd remove/replace "given" from the name, maybe "mount_bpffs_for_file"?

> +{
> +	char err_str[ERR_MAX_LEN];
> +	char *temp_name;
> +	char *dir;
> +	int err = 0;
> +
> +	if (access(file_name, F_OK) != -1) {
> +		p_err("bpf object can't be pinned since file (%s) already exists", file_name);

I'd remove "file", the existing object might be a directory and it might
be confusing.

> +		return -1;
> +	}
> +
> +	temp_name = malloc(strlen(file_name) + 1);
> +	if (!temp_name) {
>  		p_err("mem alloc failed");
>  		return -1;
>  	}
>  
> -	strcpy(file, name);
> -	dir = dirname(file);
> +	strcpy(temp_name, file_name);
> +	dir = dirname(temp_name);
>  

Here, we could check for the existence of "dir", and error out
otherwise. The reason is that with the current code, if dir does not
exist but user passes --nomount, then we fail to pin the path (given
that the directory is not present), but the message returned will be "no
BPF file system found, not mounting it due to --nomount option", which
is confusing.

Same note applies to the other function as well.

>  	if (is_bpffs(dir))
>  		/* nothing to do if already mounted */
> @@ -277,11 +333,11 @@ int mount_bpffs_for_pin(const char *name, bool is_dir)
>  	if (err) {
>  		err_str[ERR_MAX_LEN - 1] = '\0';
>  		p_err("can't mount BPF file system to pin the object (%s): %s",

We could also indicate the path where we tried to mount the bpffs, in
this message.

> -		      name, err_str);
> +		      file_name, err_str);
>  	}
>  
>  out_free:
> -	free(file);
> +	free(temp_name);
>  	return err;
>  }
>  
> @@ -289,7 +345,7 @@ int do_pin_fd(int fd, const char *name)
>  {
>  	int err;
>  
> -	err = mount_bpffs_for_pin(name, false);
> +	err = mount_bpffs_given_file(name);
>  	if (err)
>  		return err;
>  
> diff --git a/tools/bpf/bpftool/iter.c b/tools/bpf/bpftool/iter.c
> index 6b0e5202ca7a..3911563dcc60 100644
> --- a/tools/bpf/bpftool/iter.c
> +++ b/tools/bpf/bpftool/iter.c
> @@ -76,7 +76,7 @@ static int do_pin(int argc, char **argv)
>  		goto close_obj;
>  	}
>  
> -	err = mount_bpffs_for_pin(path, false);
> +	err = mount_bpffs_given_file(path);
>  	if (err)
>  		goto close_link;
>  
> diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
> index b8bb08d10dec..20e06ad183ec 100644
> --- a/tools/bpf/bpftool/main.h
> +++ b/tools/bpf/bpftool/main.h
> @@ -142,7 +142,8 @@ const char *get_fd_type_name(enum bpf_obj_type type);
>  char *get_fdinfo(int fd, const char *key);
>  int open_obj_pinned(const char *path, bool quiet);
>  int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type);
> -int mount_bpffs_for_pin(const char *name, bool is_dir);
> +int mount_bpffs_given_file(const char *file_name);
> +int mount_bpffs_on_dir(const char *dir_name);
>  int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(int *, char ***));
>  int do_pin_fd(int fd, const char *name);
>  
> diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
> index 9cb42a3366c0..09b5f0415a5e 100644
> --- a/tools/bpf/bpftool/prog.c
> +++ b/tools/bpf/bpftool/prog.c
> @@ -1778,7 +1778,10 @@ static int load_with_options(int argc, char **argv, bool first_prog_only)
>  		goto err_close_obj;
>  	}
>  
> -	err = mount_bpffs_for_pin(pinfile, !first_prog_only);
> +	if (first_prog_only)
> +		err = mount_bpffs_given_file(pinfile);
> +	else
> +		err = mount_bpffs_on_dir(pinfile);
>  	if (err)
>  		goto err_close_obj;
>  
> diff --git a/tools/bpf/bpftool/struct_ops.c b/tools/bpf/bpftool/struct_ops.c
> index d573f2640d8e..bf50a99b2501 100644
> --- a/tools/bpf/bpftool/struct_ops.c
> +++ b/tools/bpf/bpftool/struct_ops.c
> @@ -515,7 +515,7 @@ static int do_register(int argc, char **argv)
>  	if (argc == 1)
>  		linkdir = GET_ARG();
>  
> -	if (linkdir && mount_bpffs_for_pin(linkdir, true)) {
> +	if (linkdir && mount_bpffs_on_dir(linkdir)) {
>  		p_err("can't mount bpffs for pinning");
>  		return -1;
>  	}

Other than the comments above, the patch works well, and the different
cases are much easier to follow than in v1, thanks!

I've checked that the programs load as expected, the directories are
created (or not) as expected, and the bpffs is mounted (or not) as
expected, for all the cases I could think of, with the following
commands (copied here, for the record), all worked as I expected:

    mkdir -p /sys/fs/bpf/some_dir
    mkdir -p /tmp/test-dir/some_dir

    # /tmp/ret.o contains 1 program, /tmp/rets.o contains several ones

    # Load one program under bpffs
    bpftool prog load /tmp/ret.o /sys/fs/bpf/foo type xdp
    mount | grep bpf
    ls /sys/fs/bpf/foo

    # Try to load one program when pin path exists, under bpffs
    bpftool prog load /tmp/ret.o /sys/fs/bpf/foo type xdp
    mount | grep bpf
    ls /sys/fs/bpf/foo
    rm /sys/fs/bpf/foo

    # Load one program under bpffs, with --nomount
    bpftool --nomount prog load /tmp/ret.o /sys/fs/bpf/foo type xdp
    mount | grep bpf
    ls /sys/fs/bpf/foo
    rm /sys/fs/bpf/foo

    # Load one program outside of bpffs, with --nomount
    bpftool --nomount prog load /tmp/ret.o /tmp/test-dir/foo type xdp
    mount | grep bpf
    ls /tmp/test-dir/foo
    # Load one program outside of bpffs
    bpftool prog load /tmp/ret.o /tmp/test-dir/foo type xdp
    mount | grep bpf
    ls /tmp/test-dir/foo
    # Try to load one program when pin path exists, outside of bpffs
    bpftool prog load /tmp/ret.o /tmp/test-dir/foo type xdp
    mount | grep bpf
    rm /tmp/test-dir/foo
    umount /tmp/test-dir
    umount /tmp/test-dir

    # Load multiple programs under bpffs, directory exists
    bpftool prog loadall /tmp/rets.o /sys/fs/bpf/some_dir
    mount | grep bpf
    ls /sys/fs/bpf/some_dir
    rm /sys/fs/bpf/some_dir/*
    # Load multiple programs under bpffs, with -n, directory exists
    bpftool --nomount prog loadall /tmp/rets.o /sys/fs/bpf/some_dir
    mount | grep bpf
    ls /sys/fs/bpf/some_dir
    rm /sys/fs/bpf/some_dir/*

    # Load multiple programs under bpffs, directory does not exist
    bpftool prog loadall /tmp/rets.o /sys/fs/bpf/new_dir
    mount | grep bpf
    ls /sys/fs/bpf/new_dir
    rm -r /sys/fs/bpf/new_dir
    # Load multiple progs under bpffs, with -n, directory doesn't exist
    bpftool --nomount prog loadall /tmp/rets.o /sys/fs/bpf/new_dir
    mount | grep bpf
    ls /sys/fs/bpf/new_dir
    rm -r /sys/fs/bpf/new_dir

    # Load multiple programs outside of bpffs, directory exists
    bpftool prog loadall /tmp/rets.o /tmp/test-dir/some_dir
    mount | grep bpf
    ls /tmp/test-dir/some_dir
    rm /tmp/test-dir/some_dir/*
    umount /tmp/test-dir/some_dir
    umount /tmp/test-dir/some_dir
    # Try to load multiple progs outside of bpffs, with -n, dir exists
    bpftool --nomount prog loadall /tmp/rets.o /tmp/test-dir/some_dir
    mount | grep bpf
    ls /tmp/test-dir/some_dir

    # Load multiple programs outside of bpffs, directory does not exist
    bpftool prog loadall /tmp/rets.o /tmp/test-dir/new_dir
    mount | grep bpf
    ls /tmp/test-dir/new_dir
    umount /tmp/test-dir/new_dir
    umount /tmp/test-dir/new_dir
    rm -r /tmp/test-dir/new_dir
    # Try to load multiple progs outside of bpffs, with -n, new dir
    bpftool --nomount prog loadall /tmp/rets.o /tmp/test-dir/new_dir
    mount | grep bpf
    ls /tmp/test-dir/new_dir
    rm -r /tmp/test-dir

Thanks,
Quentin
Sahil Siddiq March 14, 2024, 9:16 p.m. UTC | #2
Hi,

On Wednesday, March 13, 2024 9:17:44 PM IST Quentin Monnet wrote:
> Thanks! Apologies for the delay.

No worries! Thank you for the review.

> [...]
> Note: you don't need the blank lines between the tags.
> [...]
> You can keep the changelog as part of the patch description.

Got it. I'll keep this in mind when I submit v3.

> [...]
> With all the checks and the potential directory creation, we could maybe
> rename this into "prepare_bpffs_dir()" or something like this?

"prepare_bpffs_dir" is quite apt. If longer names are acceptable then I
would also recommend "prepare_and_mount_bpffs_dir" so it indicates
that it'll also mount the bpffs on the dir (when relevant) after performing
the checks.

> [...]
> I'd maybe change this block a little (although it's up to you):
> 
> 	bool dir_exists;
> 
> 	dire_exists = (access(...) == 0);
> 	if (!dir_exists) {
> 		...
> 		free(temp_name);
> 	}
> 
> 	if (block_mount) {
> 		...
> 	}
> 
> 	if (!dir_exists) {
> 		err = mkdir(...);
> 		...
> 	}
> 
> 	err = mnt_fs(...);
> 	...
> 
> This would also enable us to remove the directory we just created, if
> we're not able to mount the bpffs on it, before leaving the function.

I agree with this. This will also keep the implementation a little more
succinct with just one "block_mount" conditional block.

> [...]
> I'd remove/replace "given" from the name, maybe "mount_bpffs_for_file"?

This is definitely a better name. I am not very good when it comes to
making up names :P

> [...]
> I'd remove "file", the existing object might be a directory and it might
> be confusing.
> 
> > +		return -1;
> > +	}
> > +
> > +	temp_name = malloc(strlen(file_name) + 1);
> > +	if (!temp_name) {
> > 
> >  		p_err("mem alloc failed");
> >  		return -1;
> >  	
> >  	}
> > 
> > -	strcpy(file, name);
> > -	dir = dirname(file);
> > +	strcpy(temp_name, file_name);
> > +	dir = dirname(temp_name);
> 
> Here, we could check for the existence of "dir", and error out
> otherwise. The reason is that with the current code, if dir does not
> exist but user passes --nomount, then we fail to pin the path (given
> that the directory is not present), but the message returned will be "no
> BPF file system found, not mounting it due to --nomount option", which
> is confusing.
> 
> Same note applies to the other function as well.
> 
> >  	if (is_bpffs(dir))
> >  	
> >  		/* nothing to do if already mounted */
> > 
> > @@ -277,11 +333,11 @@ int mount_bpffs_for_pin(const char *name, bool
> > is_dir)> 
> >  	if (err) {
> >  	
> >  		err_str[ERR_MAX_LEN - 1] = '\0';
> >  		p_err("can't mount BPF file system to pin the object (%s): %s",
> 
> We could also indicate the path where we tried to mount the bpffs, in
> this message.

Understood. I'll make these changes as well.

> [...]
> Other than the comments above, the patch works well, and the different
> cases are much easier to follow than in v1, thanks!
> 
> I've checked that the programs load as expected, the directories are
> created (or not) as expected, and the bpffs is mounted (or not) as
> expected, for all the cases I could think of, with the following
> commands (copied here, for the record), all worked as I expected:

That's really nice to hear. I'll incorporate the recommended changes and
will send v3 soon.

Thanks,
Sahil
Quentin Monnet March 15, 2024, 9:59 a.m. UTC | #3
2024-03-14 21:16 UTC+0000 ~ Sahil <icegambit91@gmail.com>
> Hi,
> 
> On Wednesday, March 13, 2024 9:17:44 PM IST Quentin Monnet wrote:
>> Thanks! Apologies for the delay.
> 
> No worries! Thank you for the review.
> 
>> [...]
>> Note: you don't need the blank lines between the tags.
>> [...]
>> You can keep the changelog as part of the patch description.
> 
> Got it. I'll keep this in mind when I submit v3.
> 
>> [...]
>> With all the checks and the potential directory creation, we could maybe
>> rename this into "prepare_bpffs_dir()" or something like this?
> 
> "prepare_bpffs_dir" is quite apt. If longer names are acceptable then I
> would also recommend "prepare_and_mount_bpffs_dir" so it indicates
> that it'll also mount the bpffs on the dir (when relevant) after performing
> the checks.

The length looks acceptable to me. I used "prepare" to summarise "create
and mount", if you prefer "mount" explicitly then maybe
"create_and_mount_bpffs_dir()"? There's no other preparation step as far
as I remember so we should as well make it clear.

> That's really nice to hear. I'll incorporate the recommended changes and
> will send v3 soon.

Thanks a lot,
Quentin
Sahil Siddiq March 21, 2024, 7:22 p.m. UTC | #4
Hi,

Sorry for the delay in my response. I have made
the relevant changes and have sent v3.

Thanks,
Sahil
diff mbox series

Patch

diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
index cc6e6aae2447..d2746681200e 100644
--- a/tools/bpf/bpftool/common.c
+++ b/tools/bpf/bpftool/common.c
@@ -244,24 +244,80 @@  int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type)
 	return fd;
 }
 
-int mount_bpffs_for_pin(const char *name, bool is_dir)
+int mount_bpffs_on_dir(const char *dir_name)
 {
 	char err_str[ERR_MAX_LEN];
-	char *file;
-	char *dir;
 	int err = 0;
 
-	if (is_dir && is_bpffs(name))
+	if (is_bpffs(dir_name))
 		return err;
 
-	file = malloc(strlen(name) + 1);
-	if (!file) {
+	if (access(dir_name, F_OK) == -1) {
+		char *temp_name;
+		char *parent_name;
+
+		temp_name = malloc(strlen(dir_name) + 1);
+		if (!temp_name) {
+			p_err("mem alloc failed");
+			return -1;
+		}
+
+		strcpy(temp_name, dir_name);
+		parent_name = dirname(temp_name);
+
+		if (is_bpffs(parent_name)) {
+			/* nothing to do if already mounted */
+			free(temp_name);
+			return err;
+		}
+
+		free(temp_name);
+
+		if (block_mount) {
+			p_err("no BPF file system found, not mounting it due to --nomount option");
+			return -1;
+		}
+
+		err = mkdir(dir_name, 0700);
+		if (err) {
+			p_err("failed to create dir (%s): %s", dir_name, strerror(errno));
+			return err;
+		}
+	} else if (block_mount) {
+		p_err("no BPF file system found, not mounting it due to --nomount option");
+		return -1;
+	}
+
+	err = mnt_fs(dir_name, "bpf", err_str, ERR_MAX_LEN);
+	if (err) {
+		err_str[ERR_MAX_LEN - 1] = '\0';
+		p_err("can't mount BPF file system on given dir (%s): %s",
+		      dir_name, err_str);
+	}
+
+	return err;
+}
+
+int mount_bpffs_given_file(const char *file_name)
+{
+	char err_str[ERR_MAX_LEN];
+	char *temp_name;
+	char *dir;
+	int err = 0;
+
+	if (access(file_name, F_OK) != -1) {
+		p_err("bpf object can't be pinned since file (%s) already exists", file_name);
+		return -1;
+	}
+
+	temp_name = malloc(strlen(file_name) + 1);
+	if (!temp_name) {
 		p_err("mem alloc failed");
 		return -1;
 	}
 
-	strcpy(file, name);
-	dir = dirname(file);
+	strcpy(temp_name, file_name);
+	dir = dirname(temp_name);
 
 	if (is_bpffs(dir))
 		/* nothing to do if already mounted */
@@ -277,11 +333,11 @@  int mount_bpffs_for_pin(const char *name, bool is_dir)
 	if (err) {
 		err_str[ERR_MAX_LEN - 1] = '\0';
 		p_err("can't mount BPF file system to pin the object (%s): %s",
-		      name, err_str);
+		      file_name, err_str);
 	}
 
 out_free:
-	free(file);
+	free(temp_name);
 	return err;
 }
 
@@ -289,7 +345,7 @@  int do_pin_fd(int fd, const char *name)
 {
 	int err;
 
-	err = mount_bpffs_for_pin(name, false);
+	err = mount_bpffs_given_file(name);
 	if (err)
 		return err;
 
diff --git a/tools/bpf/bpftool/iter.c b/tools/bpf/bpftool/iter.c
index 6b0e5202ca7a..3911563dcc60 100644
--- a/tools/bpf/bpftool/iter.c
+++ b/tools/bpf/bpftool/iter.c
@@ -76,7 +76,7 @@  static int do_pin(int argc, char **argv)
 		goto close_obj;
 	}
 
-	err = mount_bpffs_for_pin(path, false);
+	err = mount_bpffs_given_file(path);
 	if (err)
 		goto close_link;
 
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index b8bb08d10dec..20e06ad183ec 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -142,7 +142,8 @@  const char *get_fd_type_name(enum bpf_obj_type type);
 char *get_fdinfo(int fd, const char *key);
 int open_obj_pinned(const char *path, bool quiet);
 int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type);
-int mount_bpffs_for_pin(const char *name, bool is_dir);
+int mount_bpffs_given_file(const char *file_name);
+int mount_bpffs_on_dir(const char *dir_name);
 int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(int *, char ***));
 int do_pin_fd(int fd, const char *name);
 
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index 9cb42a3366c0..09b5f0415a5e 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -1778,7 +1778,10 @@  static int load_with_options(int argc, char **argv, bool first_prog_only)
 		goto err_close_obj;
 	}
 
-	err = mount_bpffs_for_pin(pinfile, !first_prog_only);
+	if (first_prog_only)
+		err = mount_bpffs_given_file(pinfile);
+	else
+		err = mount_bpffs_on_dir(pinfile);
 	if (err)
 		goto err_close_obj;
 
diff --git a/tools/bpf/bpftool/struct_ops.c b/tools/bpf/bpftool/struct_ops.c
index d573f2640d8e..bf50a99b2501 100644
--- a/tools/bpf/bpftool/struct_ops.c
+++ b/tools/bpf/bpftool/struct_ops.c
@@ -515,7 +515,7 @@  static int do_register(int argc, char **argv)
 	if (argc == 1)
 		linkdir = GET_ARG();
 
-	if (linkdir && mount_bpffs_for_pin(linkdir, true)) {
+	if (linkdir && mount_bpffs_on_dir(linkdir)) {
 		p_err("can't mount bpffs for pinning");
 		return -1;
 	}