Skip to content

Commit 0f5d545

Browse files
author
Alexei Starovoitov
committed
Merge branch 'bpf-fs-mount-options-parsing-follow-ups'
Andrii Nakryiko says: ==================== BPF FS mount options parsing follow ups Original BPF token patch set ([0]) added delegate_xxx mount options which supported only special "any" value and hexadecimal bitmask. This patch set attempts to make specifying and inspecting these mount options more human-friendly by supporting string constants matching corresponding bpf_cmd, bpf_map_type, bpf_prog_type, and bpf_attach_type enumerators. This implementation relies on BTF information to find all supported symbolic names. If kernel wasn't built with BTF, BPF FS will still support "any" and hex-based mask. [0] https://patchwork.kernel.org/project/netdevbpf/list/?series=805707&state=* v1->v2: - strip BPF_, BPF_MAP_TYPE_, and BPF_PROG_TYPE_ prefixes, do case-insensitive comparison, normalize to lower case (Alexei). ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
2 parents 403f3e8 + f2d0ffe commit 0f5d545

File tree

2 files changed

+243
-58
lines changed

2 files changed

+243
-58
lines changed

kernel/bpf/inode.c

Lines changed: 211 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,136 @@ struct bpf_prog *bpf_prog_get_type_path(const char *name, enum bpf_prog_type typ
595595
}
596596
EXPORT_SYMBOL(bpf_prog_get_type_path);
597597

598+
struct bpffs_btf_enums {
599+
const struct btf *btf;
600+
const struct btf_type *cmd_t;
601+
const struct btf_type *map_t;
602+
const struct btf_type *prog_t;
603+
const struct btf_type *attach_t;
604+
};
605+
606+
static int find_bpffs_btf_enums(struct bpffs_btf_enums *info)
607+
{
608+
const struct btf *btf;
609+
const struct btf_type *t;
610+
const char *name;
611+
int i, n;
612+
613+
memset(info, 0, sizeof(*info));
614+
615+
btf = bpf_get_btf_vmlinux();
616+
if (IS_ERR(btf))
617+
return PTR_ERR(btf);
618+
if (!btf)
619+
return -ENOENT;
620+
621+
info->btf = btf;
622+
623+
for (i = 1, n = btf_nr_types(btf); i < n; i++) {
624+
t = btf_type_by_id(btf, i);
625+
if (!btf_type_is_enum(t))
626+
continue;
627+
628+
name = btf_name_by_offset(btf, t->name_off);
629+
if (!name)
630+
continue;
631+
632+
if (strcmp(name, "bpf_cmd") == 0)
633+
info->cmd_t = t;
634+
else if (strcmp(name, "bpf_map_type") == 0)
635+
info->map_t = t;
636+
else if (strcmp(name, "bpf_prog_type") == 0)
637+
info->prog_t = t;
638+
else if (strcmp(name, "bpf_attach_type") == 0)
639+
info->attach_t = t;
640+
else
641+
continue;
642+
643+
if (info->cmd_t && info->map_t && info->prog_t && info->attach_t)
644+
return 0;
645+
}
646+
647+
return -ESRCH;
648+
}
649+
650+
static bool find_btf_enum_const(const struct btf *btf, const struct btf_type *enum_t,
651+
const char *prefix, const char *str, int *value)
652+
{
653+
const struct btf_enum *e;
654+
const char *name;
655+
int i, n, pfx_len = strlen(prefix);
656+
657+
*value = 0;
658+
659+
if (!btf || !enum_t)
660+
return false;
661+
662+
for (i = 0, n = btf_vlen(enum_t); i < n; i++) {
663+
e = &btf_enum(enum_t)[i];
664+
665+
name = btf_name_by_offset(btf, e->name_off);
666+
if (!name || strncasecmp(name, prefix, pfx_len) != 0)
667+
continue;
668+
669+
/* match symbolic name case insensitive and ignoring prefix */
670+
if (strcasecmp(name + pfx_len, str) == 0) {
671+
*value = e->val;
672+
return true;
673+
}
674+
}
675+
676+
return false;
677+
}
678+
679+
static void seq_print_delegate_opts(struct seq_file *m,
680+
const char *opt_name,
681+
const struct btf *btf,
682+
const struct btf_type *enum_t,
683+
const char *prefix,
684+
u64 delegate_msk, u64 any_msk)
685+
{
686+
const struct btf_enum *e;
687+
bool first = true;
688+
const char *name;
689+
u64 msk;
690+
int i, n, pfx_len = strlen(prefix);
691+
692+
delegate_msk &= any_msk; /* clear unknown bits */
693+
694+
if (delegate_msk == 0)
695+
return;
696+
697+
seq_printf(m, ",%s", opt_name);
698+
if (delegate_msk == any_msk) {
699+
seq_printf(m, "=any");
700+
return;
701+
}
702+
703+
if (btf && enum_t) {
704+
for (i = 0, n = btf_vlen(enum_t); i < n; i++) {
705+
e = &btf_enum(enum_t)[i];
706+
name = btf_name_by_offset(btf, e->name_off);
707+
if (!name || strncasecmp(name, prefix, pfx_len) != 0)
708+
continue;
709+
msk = 1ULL << e->val;
710+
if (delegate_msk & msk) {
711+
/* emit lower-case name without prefix */
712+
seq_printf(m, "%c", first ? '=' : ':');
713+
name += pfx_len;
714+
while (*name) {
715+
seq_printf(m, "%c", tolower(*name));
716+
name++;
717+
}
718+
719+
delegate_msk &= ~msk;
720+
first = false;
721+
}
722+
}
723+
}
724+
if (delegate_msk)
725+
seq_printf(m, "%c0x%llx", first ? '=' : ':', delegate_msk);
726+
}
727+
598728
/*
599729
* Display the mount options in /proc/mounts.
600730
*/
@@ -614,29 +744,34 @@ static int bpf_show_options(struct seq_file *m, struct dentry *root)
614744
if (mode != S_IRWXUGO)
615745
seq_printf(m, ",mode=%o", mode);
616746

617-
mask = (1ULL << __MAX_BPF_CMD) - 1;
618-
if ((opts->delegate_cmds & mask) == mask)
619-
seq_printf(m, ",delegate_cmds=any");
620-
else if (opts->delegate_cmds)
621-
seq_printf(m, ",delegate_cmds=0x%llx", opts->delegate_cmds);
622-
623-
mask = (1ULL << __MAX_BPF_MAP_TYPE) - 1;
624-
if ((opts->delegate_maps & mask) == mask)
625-
seq_printf(m, ",delegate_maps=any");
626-
else if (opts->delegate_maps)
627-
seq_printf(m, ",delegate_maps=0x%llx", opts->delegate_maps);
628-
629-
mask = (1ULL << __MAX_BPF_PROG_TYPE) - 1;
630-
if ((opts->delegate_progs & mask) == mask)
631-
seq_printf(m, ",delegate_progs=any");
632-
else if (opts->delegate_progs)
633-
seq_printf(m, ",delegate_progs=0x%llx", opts->delegate_progs);
634-
635-
mask = (1ULL << __MAX_BPF_ATTACH_TYPE) - 1;
636-
if ((opts->delegate_attachs & mask) == mask)
637-
seq_printf(m, ",delegate_attachs=any");
638-
else if (opts->delegate_attachs)
639-
seq_printf(m, ",delegate_attachs=0x%llx", opts->delegate_attachs);
747+
if (opts->delegate_cmds || opts->delegate_maps ||
748+
opts->delegate_progs || opts->delegate_attachs) {
749+
struct bpffs_btf_enums info;
750+
751+
/* ignore errors, fallback to hex */
752+
(void)find_bpffs_btf_enums(&info);
753+
754+
mask = (1ULL << __MAX_BPF_CMD) - 1;
755+
seq_print_delegate_opts(m, "delegate_cmds",
756+
info.btf, info.cmd_t, "BPF_",
757+
opts->delegate_cmds, mask);
758+
759+
mask = (1ULL << __MAX_BPF_MAP_TYPE) - 1;
760+
seq_print_delegate_opts(m, "delegate_maps",
761+
info.btf, info.map_t, "BPF_MAP_TYPE_",
762+
opts->delegate_maps, mask);
763+
764+
mask = (1ULL << __MAX_BPF_PROG_TYPE) - 1;
765+
seq_print_delegate_opts(m, "delegate_progs",
766+
info.btf, info.prog_t, "BPF_PROG_TYPE_",
767+
opts->delegate_progs, mask);
768+
769+
mask = (1ULL << __MAX_BPF_ATTACH_TYPE) - 1;
770+
seq_print_delegate_opts(m, "delegate_attachs",
771+
info.btf, info.attach_t, "BPF_",
772+
opts->delegate_attachs, mask);
773+
}
774+
640775
return 0;
641776
}
642777

@@ -686,7 +821,6 @@ static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param)
686821
kuid_t uid;
687822
kgid_t gid;
688823
int opt, err;
689-
u64 msk;
690824

691825
opt = fs_parse(fc, bpf_fs_parameters, param, &result);
692826
if (opt < 0) {
@@ -741,24 +875,63 @@ static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param)
741875
case OPT_DELEGATE_CMDS:
742876
case OPT_DELEGATE_MAPS:
743877
case OPT_DELEGATE_PROGS:
744-
case OPT_DELEGATE_ATTACHS:
745-
if (strcmp(param->string, "any") == 0) {
746-
msk = ~0ULL;
747-
} else {
748-
err = kstrtou64(param->string, 0, &msk);
749-
if (err)
750-
return err;
878+
case OPT_DELEGATE_ATTACHS: {
879+
struct bpffs_btf_enums info;
880+
const struct btf_type *enum_t;
881+
const char *enum_pfx;
882+
u64 *delegate_msk, msk = 0;
883+
char *p;
884+
int val;
885+
886+
/* ignore errors, fallback to hex */
887+
(void)find_bpffs_btf_enums(&info);
888+
889+
switch (opt) {
890+
case OPT_DELEGATE_CMDS:
891+
delegate_msk = &opts->delegate_cmds;
892+
enum_t = info.cmd_t;
893+
enum_pfx = "BPF_";
894+
break;
895+
case OPT_DELEGATE_MAPS:
896+
delegate_msk = &opts->delegate_maps;
897+
enum_t = info.map_t;
898+
enum_pfx = "BPF_MAP_TYPE_";
899+
break;
900+
case OPT_DELEGATE_PROGS:
901+
delegate_msk = &opts->delegate_progs;
902+
enum_t = info.prog_t;
903+
enum_pfx = "BPF_PROG_TYPE_";
904+
break;
905+
case OPT_DELEGATE_ATTACHS:
906+
delegate_msk = &opts->delegate_attachs;
907+
enum_t = info.attach_t;
908+
enum_pfx = "BPF_";
909+
break;
910+
default:
911+
return -EINVAL;
751912
}
913+
914+
while ((p = strsep(&param->string, ":"))) {
915+
if (strcmp(p, "any") == 0) {
916+
msk |= ~0ULL;
917+
} else if (find_btf_enum_const(info.btf, enum_t, enum_pfx, p, &val)) {
918+
msk |= 1ULL << val;
919+
} else {
920+
err = kstrtou64(p, 0, &msk);
921+
if (err)
922+
return err;
923+
}
924+
}
925+
752926
/* Setting delegation mount options requires privileges */
753927
if (msk && !capable(CAP_SYS_ADMIN))
754928
return -EPERM;
755-
switch (opt) {
756-
case OPT_DELEGATE_CMDS: opts->delegate_cmds |= msk; break;
757-
case OPT_DELEGATE_MAPS: opts->delegate_maps |= msk; break;
758-
case OPT_DELEGATE_PROGS: opts->delegate_progs |= msk; break;
759-
case OPT_DELEGATE_ATTACHS: opts->delegate_attachs |= msk; break;
760-
default: return -EINVAL;
761-
}
929+
930+
*delegate_msk |= msk;
931+
break;
932+
}
933+
default:
934+
/* ignore unknown mount options */
762935
break;
763936
}
764937

0 commit comments

Comments
 (0)