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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Thanks! Apologies for the delay.

2024-03-08 13:07 UTC+0000 ~ Sahil Siddiq <icegambit91@xxxxxxxxx>
> 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@xxxxxxxxxxxxx/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@xxxxxxxxx>

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




[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux