From c55f839cf7bfdb290b1d6c5814935835f8a46146 Mon Sep 17 00:00:00 2001
From: Lianbo Jiang <lijiang@redhat.com>
Date: Thu, 20 Jan 2022 22:06:37 +0800
Subject: [PATCH] Fix for "bpf -m|-M" options to appropriately display MEMLOCK
 and UID

Kernel commit 80ee81e0403c ("bpf: Eliminate rlimit-based memory
accounting infra for bpf maps") removed the struct bpf_map_memory
member from struct bpf_map.  Without the patch, the "bpf -m|-M" options
will print "(unknown)" for MEMLOCK and UID:

crash> bpf -m 1
 ID      BPF_MAP          BPF_MAP_TYPE     MAP_FLAGS
 1   ffff96ba41804400        ARRAY          00000000
     KEY_SIZE: 4  VALUE_SIZE: 8  MAX_ENTRIES: 64  MEMLOCK: (unknown)
     NAME: "dist"  UID: (unknown)

Signed-off-by: Lianbo Jiang <lijiang@redhat.com>
Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com>
---
 bpf.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 66 insertions(+), 4 deletions(-)

diff --git a/bpf.c b/bpf.c
index cb6b0ed385f9..a384f75ead17 100644
--- a/bpf.c
+++ b/bpf.c
@@ -63,6 +63,64 @@ static int do_old_idr(int, ulong, struct list_pair *);
 #define PROG_VERBOSE  (0x40)
 #define MAP_VERBOSE   (0x80)
 
+/*
+ * See the definition of bpf_map_type:
+ * include/uapi/linux/bpf.h
+ */
+/* for map_is_per_cpu() */
+#define BPF_MAP_TYPE_PERCPU_HASH            (5UL)
+#define BPF_MAP_TYPE_PERCPU_ARRAY           (6UL)
+#define BPF_MAP_TYPE_LRU_PERCPU_HASH       (10UL)
+#define BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE (21UL)
+
+/* for map_is_fd_map() */
+#define BPF_MAP_TYPE_PROG_ARRAY             (3UL)
+#define BPF_MAP_TYPE_PERF_EVENT_ARRAY       (4UL)
+#define BPF_MAP_TYPE_CGROUP_ARRAY           (8UL)
+#define BPF_MAP_TYPE_ARRAY_OF_MAPS         (12UL)
+#define BPF_MAP_TYPE_HASH_OF_MAPS          (13UL)
+
+static int map_is_per_cpu(int type)
+{
+	return type == BPF_MAP_TYPE_PERCPU_HASH ||
+	       type == BPF_MAP_TYPE_PERCPU_ARRAY ||
+	       type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
+	       type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE;
+}
+
+static int map_is_fd_map(int type)
+{
+	return type == BPF_MAP_TYPE_PROG_ARRAY ||
+	       type == BPF_MAP_TYPE_PERF_EVENT_ARRAY ||
+	       type == BPF_MAP_TYPE_CGROUP_ARRAY ||
+	       type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
+	       type == BPF_MAP_TYPE_HASH_OF_MAPS;
+}
+
+static ulong bpf_map_memory_size(int map_type, uint value_size,
+				uint key_size, uint max_entries)
+{
+	uint size, valsize;
+	int cpus = 0;
+
+	if (map_is_per_cpu(map_type)) {
+		cpus = get_cpus_possible();
+		if (!cpus) {
+			error(WARNING, "cpu_possible_map does not exist, possible cpus: %d\n", cpus);
+			return 0;
+		}
+
+		valsize = roundup(value_size, 8) * cpus;
+	} else if (map_is_fd_map(map_type))
+		valsize = sizeof(uint);
+	else
+		valsize = value_size;
+
+	size = roundup((key_size + valsize), 8);
+
+	return roundup((max_entries * size), PAGESIZE());
+}
+
 void
 cmd_bpf(void)
 {
@@ -332,7 +390,7 @@ do_bpf(ulong flags, ulong prog_id, ulong map_id, int radix)
 {
 	struct bpf_info *bpf;
 	int i, c, found, entries, type;
-	uint uid, map_pages, key_size, value_size, max_entries;
+	uint uid, map_pages, key_size = 0, value_size = 0, max_entries = 0;
 	ulong bpf_prog_aux, bpf_func, end_func, addr, insnsi, user;
 	ulong do_progs, do_maps;
 	ulonglong load_time;
@@ -572,6 +630,8 @@ do_map_only:
 		fprintf(fp, "\n");
 
 		if (flags & (MAP_ID|MAP_VERBOSE)) {
+			ulong memory;
+
 			fprintf(fp, "     KEY_SIZE: ");
 			if (VALID_MEMBER(bpf_map_key_size)) {
 				key_size = UINT(bpf->bpf_map_buf + OFFSET(bpf_map_key_size));
@@ -602,8 +662,10 @@ do_map_only:
 			} else if (VALID_MEMBER(bpf_map_pages)) {
 				map_pages = UINT(bpf->bpf_map_buf + OFFSET(bpf_map_pages));
 				fprintf(fp, "%d\n", map_pages * PAGESIZE());
-			} else
-				fprintf(fp, "(unknown)\n");
+			} else if ((memory = bpf_map_memory_size(type, value_size, key_size, max_entries)))
+				fprintf(fp, "%ld\n", memory);
+			else
+				fprintf(fp, "(unknown)");
 
 			fprintf(fp, "     NAME: ");
 			if (VALID_MEMBER(bpf_map_name)) {
@@ -632,7 +694,7 @@ do_map_only:
 				else
 					fprintf(fp, "(unknown)\n");
 			} else
-				fprintf(fp, "(unknown)\n");
+				fprintf(fp, "(unused)\n");
 		}
 
 		if (flags & DUMP_STRUCT) {
-- 
2.27.0

