23
23
#include <linux/mm.h>
24
24
#include <linux/slab.h>
25
25
#include <linux/vmalloc.h>
26
-
27
- #define OURMODNAME "vmalloc_demo"
26
+ #include <linux/version.h>
28
27
29
28
MODULE_AUTHOR ("Kaiwan N Billimoria" );
30
29
MODULE_DESCRIPTION ("LKP book:ch9/vmalloc_demo/: simple vmalloc() and friends demo lkm" );
@@ -38,7 +37,10 @@ MODULE_PARM_DESC(kvnum, "number of bytes to allocate with the kvmalloc(); (defau
38
37
#define KVN_MIN_BYTES 16
39
38
#define DISP_BYTES 16
40
39
41
- static void * vptr_rndm , * vptr_init , * kv , * kvarr , * vrx ;
40
+ static void * vptr_rndm , * vptr_init , * kv , * kvarr ;
41
+ #if LINUX_VERSION_CODE < KERNEL_VERSION (5 , 8 , 0 )
42
+ static void * vrx ;
43
+ #endif
42
44
43
45
static int vmalloc_try (void )
44
46
{
@@ -51,8 +53,7 @@ static int vmalloc_try(void)
51
53
pr_warn ("vmalloc failed\n" );
52
54
goto err_out1 ;
53
55
}
54
- pr_info ("1. vmalloc(): vptr_rndm = 0x%pK (actual=0x%px)\n" ,
55
- vptr_rndm , vptr_rndm );
56
+ pr_info ("1. vmalloc(): vptr_rndm = 0x%pK (actual=0x%px)\n" , vptr_rndm , vptr_rndm );
56
57
print_hex_dump_bytes (" content: " , DUMP_PREFIX_NONE , vptr_rndm , DISP_BYTES );
57
58
58
59
/* 2. vzalloc(); mem contents are set to zeroes */
@@ -61,25 +62,24 @@ static int vmalloc_try(void)
61
62
pr_warn ("vzalloc failed\n" );
62
63
goto err_out2 ;
63
64
}
64
- pr_info ("2. vzalloc(): vptr_init = 0x%pK (actual=0x%px)\n" ,
65
- vptr_init , vptr_init );
65
+ pr_info ("2. vzalloc(): vptr_init = 0x%pK (actual=0x%px)\n" , vptr_init , vptr_init );
66
66
print_hex_dump_bytes (" content: " , DUMP_PREFIX_NONE , vptr_init , DISP_BYTES );
67
67
68
- /* 3. kvmalloc(): allocate 'kvnum' bytes with the kvmalloc(); if kvnum is
69
- * large (enough), this will become a vmalloc() under the hood, else
70
- * it fals back to a kmalloc()
68
+ /* 3. kvmalloc(): allocate 'kvnum' bytes (5MB by default) with the kvmalloc();
69
+ * if kvnum is large (enough), this will become a vmalloc() under the hood,
70
+ * else it falls back to a kmalloc()
71
71
*/
72
72
kv = kvmalloc (kvnum , GFP_KERNEL );
73
73
if (!kv ) {
74
74
pr_warn ("kvmalloc failed\n" );
75
75
goto err_out3 ;
76
76
}
77
77
pr_info ("3. kvmalloc() : kv = 0x%pK (actual=0x%px)\n"
78
- " (for %d bytes)\n" , kv , kv , kvnum );
78
+ " (for %d bytes)\n" , kv , kv , kvnum );
79
79
print_hex_dump_bytes (" content: " , DUMP_PREFIX_NONE , kv , KVN_MIN_BYTES );
80
80
81
- /* 4. kcalloc(): allocate an array of 1000 64-bit quantities and zero
82
- * out the memory * /
81
+ /* 4. kcalloc(): allocate an array of 1000 64-bit quantities and zero out the memory
82
+ */
83
83
kvarr = kcalloc (1000 , sizeof (u64 ), GFP_KERNEL );
84
84
if (!kvarr ) {
85
85
pr_warn ("kcalloc failed\n" );
@@ -92,7 +92,14 @@ static int vmalloc_try(void)
92
92
#undef WR2ROMEM_BUG
93
93
/* #define WR2ROMEM_BUG */
94
94
/* 'Normal' usage: keep this commented out, else
95
- * we will crash! Read the book, Ch 9, for details :-) */
95
+ * we will crash! Read the book, Ch 9, for details ;-)
96
+ */
97
+ /*
98
+ * In 5.8.0, commit 88dca4c 'mm: remove the pgprot argument to __vmalloc'
99
+ * has removed the pgprot arg from the __vmalloc(). So, only attempt this
100
+ * when we're on kernels < 5.8.0
101
+ */
102
+ #if LINUX_VERSION_CODE < KERNEL_VERSION (5 , 8 , 0 )
96
103
vrx = __vmalloc (42 * PAGE_SIZE , GFP_KERNEL , PAGE_KERNEL_RO );
97
104
if (!vrx ) {
98
105
pr_warn ("__vmalloc failed\n" );
@@ -103,13 +110,30 @@ static int vmalloc_try(void)
103
110
/* Try reading the memory, should be fine */
104
111
print_hex_dump_bytes (" content: " , DUMP_PREFIX_NONE , vrx , DISP_BYTES );
105
112
#ifdef WR2ROMEM_BUG
106
- /* Try writing to the RO memory! We find that the kernel crashes
107
- * (emits an Oops!) */
113
+ /* Try writing to the RO memory! We should, of course, find that the kernel
114
+ * crashes (emits an Oops!)
115
+ */
116
+ pr_info ("6. Attempting to now write into a kernel vmalloc-ed region that's RO!\n" );
108
117
* (u64 * ) (vrx + 4 ) = 0xba ;
118
+ #endif /* WR2ROMEM_BUG */
119
+ #else
120
+ /*
121
+ * Logically, should now use the __vmalloc_node_range() BUT, whoops, it isn't exported!
122
+ * void *__vmalloc_node_range(unsigned long size, unsigned long align,
123
+ * unsigned long start, unsigned long end, gfp_t gfp_mask,
124
+ * pgprot_t prot, unsigned long vm_flags, int node,
125
+ * const void *caller)
126
+ */
127
+ pr_info
128
+ ("5. >= 5.8.0 : __vmalloc(): no page prot param; can use __vmalloc_node_range() but it's not exported.." );
129
+ pr_cont (" so, simply skip this case\n" );
109
130
#endif
131
+
110
132
return 0 ; /* success */
133
+ #if LINUX_VERSION_CODE < KERNEL_VERSION (5 , 8 , 0 )
111
134
err_out5 :
112
135
vfree (kvarr );
136
+ #endif
113
137
err_out4 :
114
138
vfree (kv );
115
139
err_out3 :
@@ -123,7 +147,8 @@ static int vmalloc_try(void)
123
147
static int __init vmalloc_demo_init (void )
124
148
{
125
149
if (kvnum < KVN_MIN_BYTES ) {
126
- pr_info ("kvnum must be >= %d bytes (curr it's %d bytes)\n" , KVN_MIN_BYTES , kvnum );
150
+ pr_info ("kvnum must be >= %d bytes (curr it's %d bytes)\n" , KVN_MIN_BYTES ,
151
+ kvnum );
127
152
return - EINVAL ;
128
153
}
129
154
pr_info ("inserted\n" );
@@ -133,7 +158,9 @@ static int __init vmalloc_demo_init(void)
133
158
134
159
static void __exit vmalloc_demo_exit (void )
135
160
{
161
+ #if LINUX_VERSION_CODE < KERNEL_VERSION (5 , 8 , 0 )
136
162
vfree (vrx );
163
+ #endif
137
164
kvfree (kvarr );
138
165
kvfree (kv );
139
166
vfree (vptr_init );
0 commit comments