8
8
9
9
#include <linux/prime_numbers.h>
10
10
#include <linux/sched/signal.h>
11
+ #include <linux/sizes.h>
11
12
12
13
#include <drm/drm_buddy.h>
13
14
@@ -18,6 +19,93 @@ static inline u64 get_size(int order, u64 chunk_size)
18
19
return (1 << order ) * chunk_size ;
19
20
}
20
21
22
+ static void drm_test_buddy_alloc_contiguous (struct kunit * test )
23
+ {
24
+ u64 mm_size , ps = SZ_4K , i , n_pages , total ;
25
+ struct drm_buddy_block * block ;
26
+ struct drm_buddy mm ;
27
+ LIST_HEAD (left );
28
+ LIST_HEAD (middle );
29
+ LIST_HEAD (right );
30
+ LIST_HEAD (allocated );
31
+
32
+ mm_size = 16 * 3 * SZ_4K ;
33
+
34
+ KUNIT_EXPECT_FALSE (test , drm_buddy_init (& mm , mm_size , ps ));
35
+
36
+ /*
37
+ * Idea is to fragment the address space by alternating block
38
+ * allocations between three different lists; one for left, middle and
39
+ * right. We can then free a list to simulate fragmentation. In
40
+ * particular we want to exercise the DRM_BUDDY_CONTIGUOUS_ALLOCATION,
41
+ * including the try_harder path.
42
+ */
43
+
44
+ i = 0 ;
45
+ n_pages = mm_size / ps ;
46
+ do {
47
+ struct list_head * list ;
48
+ int slot = i % 3 ;
49
+
50
+ if (slot == 0 )
51
+ list = & left ;
52
+ else if (slot == 1 )
53
+ list = & middle ;
54
+ else
55
+ list = & right ;
56
+ KUNIT_ASSERT_FALSE_MSG (test ,
57
+ drm_buddy_alloc_blocks (& mm , 0 , mm_size ,
58
+ ps , ps , list , 0 ),
59
+ "buddy_alloc hit an error size=%d\n" ,
60
+ ps );
61
+ } while (++ i < n_pages );
62
+
63
+ KUNIT_ASSERT_TRUE_MSG (test , drm_buddy_alloc_blocks (& mm , 0 , mm_size ,
64
+ 3 * ps , ps , & allocated ,
65
+ DRM_BUDDY_CONTIGUOUS_ALLOCATION ),
66
+ "buddy_alloc didn't error size=%d\n" , 3 * ps );
67
+
68
+ drm_buddy_free_list (& mm , & middle );
69
+ KUNIT_ASSERT_TRUE_MSG (test , drm_buddy_alloc_blocks (& mm , 0 , mm_size ,
70
+ 3 * ps , ps , & allocated ,
71
+ DRM_BUDDY_CONTIGUOUS_ALLOCATION ),
72
+ "buddy_alloc didn't error size=%llu\n" , 3 * ps );
73
+ KUNIT_ASSERT_TRUE_MSG (test , drm_buddy_alloc_blocks (& mm , 0 , mm_size ,
74
+ 2 * ps , ps , & allocated ,
75
+ DRM_BUDDY_CONTIGUOUS_ALLOCATION ),
76
+ "buddy_alloc didn't error size=%llu\n" , 2 * ps );
77
+
78
+ drm_buddy_free_list (& mm , & right );
79
+ KUNIT_ASSERT_TRUE_MSG (test , drm_buddy_alloc_blocks (& mm , 0 , mm_size ,
80
+ 3 * ps , ps , & allocated ,
81
+ DRM_BUDDY_CONTIGUOUS_ALLOCATION ),
82
+ "buddy_alloc didn't error size=%llu\n" , 3 * ps );
83
+ /*
84
+ * At this point we should have enough contiguous space for 2 blocks,
85
+ * however they are never buddies (since we freed middle and right) so
86
+ * will require the try_harder logic to find them.
87
+ */
88
+ KUNIT_ASSERT_FALSE_MSG (test , drm_buddy_alloc_blocks (& mm , 0 , mm_size ,
89
+ 2 * ps , ps , & allocated ,
90
+ DRM_BUDDY_CONTIGUOUS_ALLOCATION ),
91
+ "buddy_alloc hit an error size=%d\n" , 2 * ps );
92
+
93
+ drm_buddy_free_list (& mm , & left );
94
+ KUNIT_ASSERT_FALSE_MSG (test , drm_buddy_alloc_blocks (& mm , 0 , mm_size ,
95
+ 3 * ps , ps , & allocated ,
96
+ DRM_BUDDY_CONTIGUOUS_ALLOCATION ),
97
+ "buddy_alloc hit an error size=%d\n" , 3 * ps );
98
+
99
+ total = 0 ;
100
+ list_for_each_entry (block , & allocated , link )
101
+ total += drm_buddy_block_size (& mm , block );
102
+
103
+ KUNIT_ASSERT_EQ (test , total , ps * 2 + ps * 3 );
104
+
105
+ drm_buddy_free_list (& mm , & allocated );
106
+ drm_buddy_fini (& mm );
107
+ }
108
+
21
109
static void drm_test_buddy_alloc_pathological (struct kunit * test )
22
110
{
23
111
u64 mm_size , size , start = 0 ;
@@ -280,6 +368,7 @@ static struct kunit_case drm_buddy_tests[] = {
280
368
KUNIT_CASE (drm_test_buddy_alloc_optimistic ),
281
369
KUNIT_CASE (drm_test_buddy_alloc_pessimistic ),
282
370
KUNIT_CASE (drm_test_buddy_alloc_pathological ),
371
+ KUNIT_CASE (drm_test_buddy_alloc_contiguous ),
283
372
{}
284
373
};
285
374
0 commit comments