commit f294197b5511537e6b14d5e1db324f4fc4fdd3f8 Author: Dave Anderson Date: Fri Jul 6 10:57:50 2018 -0400 Support for the "bpf" command on RHEL 3.10.0-913.el7 and later 3.10-based RHEL7 kernels, which contain a backport of the upstream eBPF code, but still use the older, pre-4.11, IDR facility that does not use radix trees for linking the active bpf_prog and bpf_map structures. Without the patch, the command indicates "bpf: command not supported or applicable on this architecture or kernel". (anderson@redhat.com) diff --git a/bpf.c b/bpf.c index 427263d..8871b76 100644 --- a/bpf.c +++ b/bpf.c @@ -45,6 +45,10 @@ static void bpf_prog_gpl_compatible(char *, ulong); static void dump_xlated_plain(void *, unsigned int, int); static void print_boot_time(unsigned long long, char *, unsigned int); +static int do_old_idr(int, ulong, struct radix_tree_pair *); +#define OLD_IDR_INIT (1) +#define OLD_IDR_COUNT (2) +#define OLD_IDR_GATHER (3) #define PROG_ID (0x1) #define MAP_ID (0x2) @@ -167,7 +171,6 @@ bpf_init(struct bpf_info *bpf) !VALID_STRUCT(bpf_map) || !VALID_STRUCT(bpf_insn) || INVALID_MEMBER(bpf_prog_aux) || - INVALID_MEMBER(idr_idr_rt) || INVALID_MEMBER(bpf_prog_type) || INVALID_MEMBER(bpf_prog_tag) || INVALID_MEMBER(bpf_prog_jited_len) || @@ -210,6 +213,9 @@ bpf_init(struct bpf_info *bpf) mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "BPF_MAP"), mkstring(buf3, bpf->bpf_map_map_type_size, CENTER|LJUST, "BPF_MAP_TYPE")); + if (INVALID_MEMBER(idr_idr_rt)) + do_old_idr(OLD_IDR_INIT, 0, NULL); + bpf->status = TRUE; break; @@ -220,24 +226,38 @@ bpf_init(struct bpf_info *bpf) command_not_supported(); } - bpf->progs = do_radix_tree(symbol_value("prog_idr") + OFFSET(idr_idr_rt), - RADIX_TREE_COUNT, NULL); + if (VALID_MEMBER(idr_idr_rt)) + bpf->progs = do_radix_tree(symbol_value("prog_idr") + OFFSET(idr_idr_rt), + RADIX_TREE_COUNT, NULL); + else + bpf->progs = do_old_idr(OLD_IDR_COUNT, symbol_value("prog_idr"), NULL); + if (bpf->progs) { len = sizeof(struct radix_tree_pair) * (bpf->progs+1); bpf->proglist = (struct radix_tree_pair *)GETBUF(len); bpf->proglist[0].index = bpf->progs; - bpf->progs = do_radix_tree(symbol_value("prog_idr") + OFFSET(idr_idr_rt), - RADIX_TREE_GATHER, bpf->proglist); + if (VALID_MEMBER(idr_idr_rt)) + bpf->progs = do_radix_tree(symbol_value("prog_idr") + OFFSET(idr_idr_rt), + RADIX_TREE_GATHER, bpf->proglist); + else + bpf->progs = do_old_idr(OLD_IDR_GATHER, symbol_value("prog_idr"), bpf->proglist); } - bpf->maps = do_radix_tree(symbol_value("map_idr") + OFFSET(idr_idr_rt), - RADIX_TREE_COUNT, NULL); + if (VALID_MEMBER(idr_idr_rt)) + bpf->maps = do_radix_tree(symbol_value("map_idr") + OFFSET(idr_idr_rt), + RADIX_TREE_COUNT, NULL); + else + bpf->maps = do_old_idr(OLD_IDR_COUNT, symbol_value("map_idr"), NULL); + if (bpf->maps) { len = sizeof(struct radix_tree_pair) * (bpf->maps+1); bpf->maplist = (struct radix_tree_pair *)GETBUF(len); bpf->maplist[0].index = bpf->maps; - bpf->maps = do_radix_tree(symbol_value("map_idr") + OFFSET(idr_idr_rt), - RADIX_TREE_GATHER, bpf->maplist); + if (VALID_MEMBER(idr_idr_rt)) + bpf->maps = do_radix_tree(symbol_value("map_idr") + OFFSET(idr_idr_rt), + RADIX_TREE_GATHER, bpf->maplist); + else + bpf->maps = do_old_idr(OLD_IDR_GATHER, symbol_value("map_idr"), bpf->maplist); } bpf->bpf_prog_buf = GETBUF(SIZE(bpf_prog)); @@ -538,8 +558,10 @@ do_map_only: } bailout: - FREEBUF(bpf->proglist); - FREEBUF(bpf->maplist); + if (bpf->proglist) + FREEBUF(bpf->proglist); + if (bpf->maplist) + FREEBUF(bpf->maplist); FREEBUF(bpf->bpf_prog_buf); FREEBUF(bpf->bpf_prog_aux_buf); FREEBUF(bpf->bpf_map_buf); @@ -1255,3 +1277,50 @@ print_boot_time(unsigned long long nsecs, char *buf, unsigned int size) sprintf(buf, "(unknown)"); #endif } + +/* + * Borrow the old (pre-radix_tree) IDR facility code used by + * the ipcs command. + */ +static int +do_old_idr(int cmd, ulong idr, struct radix_tree_pair *rtp) +{ + int i, max, cur, next_id, total = 0; + ulong entry; + + switch (cmd) + { + case OLD_IDR_INIT: + ipcs_init(); + break; + + case OLD_IDR_COUNT: + readmem(idr + OFFSET(idr_cur), KVADDR, &cur, + sizeof(int), "idr.cur", FAULT_ON_ERROR); + for (total = next_id = 0; next_id < cur; next_id++) { + entry = idr_find(idr, next_id); + if (entry == 0) + continue; + total++; + } + break; + + case OLD_IDR_GATHER: + max = rtp[0].index; + readmem(idr + OFFSET(idr_cur), KVADDR, &cur, + sizeof(int), "idr.cur", FAULT_ON_ERROR); + for (i = total = next_id = 0; next_id < cur; next_id++) { + entry = idr_find(idr, next_id); + if (entry == 0) + continue; + total++; + rtp[i].index = next_id; + rtp[i].value = (void *)entry; + if (++i == max) + break; + } + break; + } + + return total; +} diff --git a/defs.h b/defs.h index e6e3850..b05aecc 100644 --- a/defs.h +++ b/defs.h @@ -2031,6 +2031,7 @@ struct offset_table { /* stash of commonly-used offsets */ long bpf_prog_aux_load_time; long bpf_prog_aux_user; long user_struct_uid; + long idr_cur; }; struct size_table { /* stash of commonly-used sizes */ @@ -5590,6 +5591,12 @@ enum { void dev_init(void); void dump_dev_table(void); +/* + * ipcs.c + */ +void ipcs_init(void); +ulong idr_find(ulong, int); + #ifdef ARM void arm_init(int); void arm_dump_machdep_table(ulong); diff --git a/ipcs.c b/ipcs.c index ef51fdd..80f78e4 100644 --- a/ipcs.c +++ b/ipcs.c @@ -79,13 +79,11 @@ struct ipcs_table { * function declaration */ -static void ipcs_init(void); static int dump_shared_memory(int, ulong, int, ulong); static int dump_semaphore_arrays(int, ulong, int, ulong); static int dump_message_queues(int, ulong, int, ulong); static int ipc_search_idr(ulong, int, ulong, int (*)(ulong, int, ulong, int, int), int); static int ipc_search_array(ulong, int, ulong, int (*)(ulong, int, ulong, int, int), int); -static ulong idr_find(ulong, int); static int dump_shm_info(ulong, int, ulong, int, int); static int dump_sem_info(ulong, int, ulong, int, int); static int dump_msg_info(ulong, int, ulong, int, int); @@ -101,7 +99,7 @@ static void gather_radix_tree_entries(ulong); */ static struct ipcs_table ipcs_table = { 0 }; -static void +void ipcs_init(void) { if (ipcs_table.init_flags & IPCS_INIT) { @@ -119,6 +117,7 @@ ipcs_init(void) MEMBER_OFFSET_INIT(idr_layer_layer, "idr_layer", "layer"); MEMBER_OFFSET_INIT(idr_layer_ary, "idr_layer", "ary"); MEMBER_OFFSET_INIT(idr_top, "idr", "top"); + MEMBER_OFFSET_INIT(idr_cur, "idr", "cur"); MEMBER_OFFSET_INIT(ipc_id_ary_p, "ipc_id_ary", "p"); MEMBER_OFFSET_INIT(ipc_ids_entries, "ipc_ids", "entries"); MEMBER_OFFSET_INIT(ipc_ids_max_id, "ipc_ids", "max_id"); @@ -188,7 +187,10 @@ ipcs_init(void) ipcs_table.shm_f_op_huge_addr = -1; } - if (BITS32()) + if (VALID_MEMBER(idr_layer_ary) && + get_array_length("idr_layer.ary", NULL, 0) > 64) + ipcs_table.idr_bits = 8; + else if (BITS32()) ipcs_table.idr_bits = 5; else if (BITS64()) ipcs_table.idr_bits = 6; @@ -635,7 +637,7 @@ ipc_search_idr(ulong ipc_ids_p, int specified, ulong specified_value, int (*fn)( /* * search every idr_layer */ -static ulong +ulong idr_find(ulong idp, int id) { ulong idr_layer_p; diff --git a/symbols.c b/symbols.c index bf55319..8ff1430 100644 --- a/symbols.c +++ b/symbols.c @@ -10041,6 +10041,8 @@ dump_offset_table(char *spec, ulong makestruct) OFFSET(idr_layers)); fprintf(fp, " idr_top: %ld\n", OFFSET(idr_top)); + fprintf(fp, " idr_cur: %ld\n", + OFFSET(idr_cur)); fprintf(fp, " ipc_id_ary_p: %ld\n", OFFSET(ipc_id_ary_p)); fprintf(fp, " ipc_ids_entries: %ld\n",