diff mbox

[3/3] vmalloc: Add debugfs modfraginfo

Message ID 1529532570-21765-4-git-send-email-rick.p.edgecombe@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Rick Edgecombe June 20, 2018, 10:09 p.m. UTC
Add debugfs file "modfraginfo" for providing info on module space
fragmentation.  This can be used for determining if loadable module
randomization is causing any problems for extreme module loading situations,
like huge numbers of modules or extremely large modules.

Sample output when RANDOMIZE_BASE and X86_64 is configured:
Largest free space:		847253504
External Memory Fragementation:	20%
Allocations in backup area:	0

Sample output otherwise:
Largest free space:		847253504
External Memory Fragementation:	20%

Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
---
 mm/vmalloc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 109 insertions(+), 1 deletion(-)

Comments

kernel test robot June 21, 2018, 12:53 a.m. UTC | #1
Hi Rick,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on mmotm/master]
[also build test ERROR on v4.18-rc1 next-20180620]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Rick-Edgecombe/KASLR-feature-to-randomize-each-loadable-module/20180621-061051
base:   git://git.cmpxchg.org/linux-mmotm.git master
config: mips-fuloong2e_defconfig (attached as .config)
compiler: mips64el-linux-gnuabi64-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.2.0 make.cross ARCH=mips 

All errors (new ones prefixed by >>):

   mm/vmalloc.c: In function 'modulefraginfo_debug_show':
>> mm/vmalloc.c:2821:27: error: 'MODULES_VADDR' undeclared (first use in this function); did you mean 'MODULE_END'?
     unsigned long last_end = MODULES_VADDR;
                              ^~~~~~~~~~~~~
                              MODULE_END
   mm/vmalloc.c:2821:27: note: each undeclared identifier is reported only once for each function it appears in
>> mm/vmalloc.c:2834:22: error: 'MODULES_END' undeclared (first use in this function); did you mean 'MODULE_END'?
       && obj->va_end <= MODULES_END) {
                         ^~~~~~~~~~~
                         MODULE_END

vim +2821 mm/vmalloc.c

  2817	
  2818	static int modulefraginfo_debug_show(struct seq_file *m, void *v)
  2819	{
  2820		struct list_head *i;
> 2821		unsigned long last_end = MODULES_VADDR;
  2822		unsigned long total_free = 0;
  2823		unsigned long largest_free = 0;
  2824		unsigned long backup_cnt = 0;
  2825		unsigned long gap;
  2826	
  2827		spin_lock(&vmap_area_lock);
  2828	
  2829		list_for_each(i, &vmap_area_list) {
  2830			struct vmap_area *obj = list_entry(i, struct vmap_area, list);
  2831	
  2832			if (!(obj->flags & VM_LAZY_FREE)
  2833				&& obj->va_start >= MODULES_VADDR
> 2834				&& obj->va_end <= MODULES_END) {
  2835	
  2836				if (obj->va_start >= get_backup_start())
  2837					backup_cnt++;
  2838	
  2839				gap = (obj->va_start - last_end);
  2840				if (gap > largest_free)
  2841					largest_free = gap;
  2842				total_free += gap;
  2843	
  2844				last_end = obj->va_end;
  2845			}
  2846		}
  2847	
  2848		gap = (MODULES_END - last_end);
  2849		if (gap > largest_free)
  2850			largest_free = gap;
  2851		total_free += gap;
  2852	
  2853		spin_unlock(&vmap_area_lock);
  2854	
  2855		seq_printf(m, "Largest free space:\t\t%lu\n", largest_free);
  2856		if (total_free)
  2857			seq_printf(m, "External Memory Fragementation:\t%lu%%\n",
  2858				100-(100*largest_free/total_free));
  2859		else
  2860			seq_puts(m, "External Memory Fragementation:\t0%%\n");
  2861	
  2862		print_backup_area(m, backup_cnt);
  2863	
  2864		return 0;
  2865	}
  2866	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
kernel test robot June 21, 2018, 1:17 a.m. UTC | #2
Hi Rick,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on mmotm/master]
[also build test ERROR on v4.18-rc1 next-20180620]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Rick-Edgecombe/KASLR-feature-to-randomize-each-loadable-module/20180621-061051
base:   git://git.cmpxchg.org/linux-mmotm.git master
config: parisc-c3000_defconfig (attached as .config)
compiler: hppa-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.2.0 make.cross ARCH=parisc 

All errors (new ones prefixed by >>):

   mm/vmalloc.c: In function 'modulefraginfo_debug_show':
>> mm/vmalloc.c:2821:27: error: 'MODULES_VADDR' undeclared (first use in this function); did you mean 'MODULE_AUTHOR'?
     unsigned long last_end = MODULES_VADDR;
                              ^~~~~~~~~~~~~
                              MODULE_AUTHOR
   mm/vmalloc.c:2821:27: note: each undeclared identifier is reported only once for each function it appears in
   mm/vmalloc.c:2834:22: error: 'MODULES_END' undeclared (first use in this function); did you mean 'MODULES_VADDR'?
       && obj->va_end <= MODULES_END) {
                         ^~~~~~~~~~~
                         MODULES_VADDR

vim +2821 mm/vmalloc.c

  2817	
  2818	static int modulefraginfo_debug_show(struct seq_file *m, void *v)
  2819	{
  2820		struct list_head *i;
> 2821		unsigned long last_end = MODULES_VADDR;
  2822		unsigned long total_free = 0;
  2823		unsigned long largest_free = 0;
  2824		unsigned long backup_cnt = 0;
  2825		unsigned long gap;
  2826	
  2827		spin_lock(&vmap_area_lock);
  2828	
  2829		list_for_each(i, &vmap_area_list) {
  2830			struct vmap_area *obj = list_entry(i, struct vmap_area, list);
  2831	
  2832			if (!(obj->flags & VM_LAZY_FREE)
  2833				&& obj->va_start >= MODULES_VADDR
  2834				&& obj->va_end <= MODULES_END) {
  2835	
  2836				if (obj->va_start >= get_backup_start())
  2837					backup_cnt++;
  2838	
  2839				gap = (obj->va_start - last_end);
  2840				if (gap > largest_free)
  2841					largest_free = gap;
  2842				total_free += gap;
  2843	
  2844				last_end = obj->va_end;
  2845			}
  2846		}
  2847	
  2848		gap = (MODULES_END - last_end);
  2849		if (gap > largest_free)
  2850			largest_free = gap;
  2851		total_free += gap;
  2852	
  2853		spin_unlock(&vmap_area_lock);
  2854	
  2855		seq_printf(m, "Largest free space:\t\t%lu\n", largest_free);
  2856		if (total_free)
  2857			seq_printf(m, "External Memory Fragementation:\t%lu%%\n",
  2858				100-(100*largest_free/total_free));
  2859		else
  2860			seq_puts(m, "External Memory Fragementation:\t0%%\n");
  2861	
  2862		print_backup_area(m, backup_cnt);
  2863	
  2864		return 0;
  2865	}
  2866	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Jann Horn June 21, 2018, 12:32 p.m. UTC | #3
On Thu, Jun 21, 2018 at 12:12 AM Rick Edgecombe
<rick.p.edgecombe@intel.com> wrote:
> Add debugfs file "modfraginfo" for providing info on module space
> fragmentation.  This can be used for determining if loadable module
> randomization is causing any problems for extreme module loading situations,
> like huge numbers of modules or extremely large modules.
>
> Sample output when RANDOMIZE_BASE and X86_64 is configured:
> Largest free space:             847253504
> External Memory Fragementation: 20%
> Allocations in backup area:     0
>
> Sample output otherwise:
> Largest free space:             847253504
> External Memory Fragementation: 20%
[...]
> +       seq_printf(m, "Largest free space:\t\t%lu\n", largest_free);
> +       if (total_free)
> +               seq_printf(m, "External Memory Fragementation:\t%lu%%\n",

"Fragmentation"

> +                       100-(100*largest_free/total_free));
> +       else
> +               seq_puts(m, "External Memory Fragementation:\t0%%\n");

"Fragmentation"

[...]
> +static const struct file_operations debug_module_frag_operations = {
> +       .open       = proc_module_frag_debug_open,
> +       .read       = seq_read,
> +       .llseek     = seq_lseek,
> +       .release    = single_release,
> +};
>
> +static void debug_modfrag_init(void)
> +{
> +       debugfs_create_file("modfraginfo", 0x0400, NULL, NULL,
> +                       &debug_module_frag_operations);

0x0400 is 02000, which is the setgid bit. I think you meant to type 0400?
Rick Edgecombe June 21, 2018, 6:56 p.m. UTC | #4
On Thu, 2018-06-21 at 14:32 +0200, Jann Horn wrote:
> On Thu, Jun 21, 2018 at 12:12 AM Rick Edgecombe

> <rick.p.edgecombe@intel.com> wrote:

> > 

> > Add debugfs file "modfraginfo" for providing info on module space

> > fragmentation.  This can be used for determining if loadable module

> > randomization is causing any problems for extreme module loading

> > situations,

> > like huge numbers of modules or extremely large modules.

> > 

> > Sample output when RANDOMIZE_BASE and X86_64 is configured:

> > Largest free space:             847253504

> > External Memory Fragementation: 20%

> > Allocations in backup area:     0

> > 

> > Sample output otherwise:

> > Largest free space:             847253504

> > External Memory Fragementation: 20%

> [...]

> > 

> > +       seq_printf(m, "Largest free space:\t\t%lu\n",

> > largest_free);

> > +       if (total_free)

> > +               seq_printf(m, "External Memory

> > Fragementation:\t%lu%%\n",

> "Fragmentation"

> 

> > 

> > +                       100-(100*largest_free/total_free));

> > +       else

> > +               seq_puts(m, "External Memory

> > Fragementation:\t0%%\n");

> "Fragmentation"


Oops! Thanks.

> [...]

> > 

> > +static const struct file_operations debug_module_frag_operations =

> > {

> > +       .open       = proc_module_frag_debug_open,

> > +       .read       = seq_read,

> > +       .llseek     = seq_lseek,

> > +       .release    = single_release,

> > +};

> > 

> > +static void debug_modfrag_init(void)

> > +{

> > +       debugfs_create_file("modfraginfo", 0x0400, NULL, NULL,

> > +                       &debug_module_frag_operations);

> 0x0400 is 02000, which is the setgid bit. I think you meant to type

> 0400?


Yes, thanks.
diff mbox

Patch

diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 9e0820c9..afb8fe9 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -18,6 +18,7 @@ 
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/debugfs.h>
 #include <linux/debugobjects.h>
 #include <linux/kallsyms.h>
 #include <linux/list.h>
@@ -33,6 +34,7 @@ 
 #include <linux/bitops.h>
 
 #include <linux/uaccess.h>
+#include <asm/setup.h>
 #include <asm/tlbflush.h>
 #include <asm/shmparam.h>
 
@@ -2785,7 +2787,113 @@  static int __init proc_vmalloc_init(void)
 		proc_create_seq("vmallocinfo", 0400, NULL, &vmalloc_op);
 	return 0;
 }
-module_init(proc_vmalloc_init);
+#else
+static int proc_vmalloc_init(void)
+{
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+#if defined(CONFIG_RANDOMIZE_BASE) && defined(CONFIG_X86_64)
+static void print_backup_area(struct seq_file *m, unsigned long backup_cnt)
+{
+	if (kaslr_enabled())
+		seq_printf(m, "Allocations in backup area:\t%lu\n", backup_cnt);
+}
+static unsigned long get_backup_start(void)
+{
+	return MODULES_VADDR + MODULES_RAND_LEN;
+}
+#else
+static void print_backup_area(struct seq_file *m, unsigned long backup_cnt)
+{
+}
+static unsigned long get_backup_start(void)
+{
+	return 0;
+}
+#endif
+
+static int modulefraginfo_debug_show(struct seq_file *m, void *v)
+{
+	struct list_head *i;
+	unsigned long last_end = MODULES_VADDR;
+	unsigned long total_free = 0;
+	unsigned long largest_free = 0;
+	unsigned long backup_cnt = 0;
+	unsigned long gap;
+
+	spin_lock(&vmap_area_lock);
+
+	list_for_each(i, &vmap_area_list) {
+		struct vmap_area *obj = list_entry(i, struct vmap_area, list);
+
+		if (!(obj->flags & VM_LAZY_FREE)
+			&& obj->va_start >= MODULES_VADDR
+			&& obj->va_end <= MODULES_END) {
+
+			if (obj->va_start >= get_backup_start())
+				backup_cnt++;
+
+			gap = (obj->va_start - last_end);
+			if (gap > largest_free)
+				largest_free = gap;
+			total_free += gap;
+
+			last_end = obj->va_end;
+		}
+	}
+
+	gap = (MODULES_END - last_end);
+	if (gap > largest_free)
+		largest_free = gap;
+	total_free += gap;
+
+	spin_unlock(&vmap_area_lock);
+
+	seq_printf(m, "Largest free space:\t\t%lu\n", largest_free);
+	if (total_free)
+		seq_printf(m, "External Memory Fragementation:\t%lu%%\n",
+			100-(100*largest_free/total_free));
+	else
+		seq_puts(m, "External Memory Fragementation:\t0%%\n");
+
+	print_backup_area(m, backup_cnt);
+
+	return 0;
+}
+
+static int proc_module_frag_debug_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, modulefraginfo_debug_show, NULL);
+}
+
+static const struct file_operations debug_module_frag_operations = {
+	.open       = proc_module_frag_debug_open,
+	.read       = seq_read,
+	.llseek     = seq_lseek,
+	.release    = single_release,
+};
 
+static void debug_modfrag_init(void)
+{
+	debugfs_create_file("modfraginfo", 0x0400, NULL, NULL,
+			&debug_module_frag_operations);
+}
+#else
+static void debug_modfrag_init(void)
+{
+}
 #endif
 
+#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_PROC_FS)
+static int __init info_vmalloc_init(void)
+{
+	proc_vmalloc_init();
+	debug_modfrag_init();
+	return 0;
+}
+
+module_init(info_vmalloc_init);
+#endif