6969#define KVM_GUESTDBG_BLOCKIRQ 0
7070#endif
7171
72+ /* Default num of memslots to be allocated when VM starts */
73+ #define KVM_MEMSLOTS_NR_ALLOC_DEFAULT 16
74+
7275struct KVMParkedVcpu {
7376 unsigned long vcpu_id ;
7477 int kvm_fd ;
@@ -165,6 +168,57 @@ void kvm_resample_fd_notify(int gsi)
165168 }
166169}
167170
171+ /**
172+ * kvm_slots_grow(): Grow the slots[] array in the KVMMemoryListener
173+ *
174+ * @kml: The KVMMemoryListener* to grow the slots[] array
175+ * @nr_slots_new: The new size of slots[] array
176+ *
177+ * Returns: True if the array grows larger, false otherwise.
178+ */
179+ static bool kvm_slots_grow (KVMMemoryListener * kml , unsigned int nr_slots_new )
180+ {
181+ unsigned int i , cur = kml -> nr_slots_allocated ;
182+ KVMSlot * slots ;
183+
184+ if (nr_slots_new > kvm_state -> nr_slots ) {
185+ nr_slots_new = kvm_state -> nr_slots ;
186+ }
187+
188+ if (cur >= nr_slots_new ) {
189+ /* Big enough, no need to grow, or we reached max */
190+ return false;
191+ }
192+
193+ if (cur == 0 ) {
194+ slots = g_new0 (KVMSlot , nr_slots_new );
195+ } else {
196+ assert (kml -> slots );
197+ slots = g_renew (KVMSlot , kml -> slots , nr_slots_new );
198+ /*
199+ * g_renew() doesn't initialize extended buffers, however kvm
200+ * memslots require fields to be zero-initialized. E.g. pointers,
201+ * memory_size field, etc.
202+ */
203+ memset (& slots [cur ], 0x0 , sizeof (slots [0 ]) * (nr_slots_new - cur ));
204+ }
205+
206+ for (i = cur ; i < nr_slots_new ; i ++ ) {
207+ slots [i ].slot = i ;
208+ }
209+
210+ kml -> slots = slots ;
211+ kml -> nr_slots_allocated = nr_slots_new ;
212+ trace_kvm_slots_grow (cur , nr_slots_new );
213+
214+ return true;
215+ }
216+
217+ static bool kvm_slots_double (KVMMemoryListener * kml )
218+ {
219+ return kvm_slots_grow (kml , kml -> nr_slots_allocated * 2 );
220+ }
221+
168222unsigned int kvm_get_max_memslots (void )
169223{
170224 KVMState * s = KVM_STATE (current_accel ());
@@ -193,15 +247,26 @@ unsigned int kvm_get_free_memslots(void)
193247/* Called with KVMMemoryListener.slots_lock held */
194248static KVMSlot * kvm_get_free_slot (KVMMemoryListener * kml )
195249{
196- KVMState * s = kvm_state ;
250+ unsigned int n ;
197251 int i ;
198252
199- for (i = 0 ; i < s -> nr_slots ; i ++ ) {
253+ for (i = 0 ; i < kml -> nr_slots_allocated ; i ++ ) {
200254 if (kml -> slots [i ].memory_size == 0 ) {
201255 return & kml -> slots [i ];
202256 }
203257 }
204258
259+ /*
260+ * If no free slots, try to grow first by doubling. Cache the old size
261+ * here to avoid another round of search: if the grow succeeded, it
262+ * means slots[] now must have the existing "n" slots occupied,
263+ * followed by one or more free slots starting from slots[n].
264+ */
265+ n = kml -> nr_slots_allocated ;
266+ if (kvm_slots_double (kml )) {
267+ return & kml -> slots [n ];
268+ }
269+
205270 return NULL ;
206271}
207272
@@ -222,10 +287,9 @@ static KVMSlot *kvm_lookup_matching_slot(KVMMemoryListener *kml,
222287 hwaddr start_addr ,
223288 hwaddr size )
224289{
225- KVMState * s = kvm_state ;
226290 int i ;
227291
228- for (i = 0 ; i < s -> nr_slots ; i ++ ) {
292+ for (i = 0 ; i < kml -> nr_slots_allocated ; i ++ ) {
229293 KVMSlot * mem = & kml -> slots [i ];
230294
231295 if (start_addr == mem -> start_addr && size == mem -> memory_size ) {
@@ -267,7 +331,7 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void *ram,
267331 int i , ret = 0 ;
268332
269333 kvm_slots_lock ();
270- for (i = 0 ; i < s -> nr_slots ; i ++ ) {
334+ for (i = 0 ; i < kml -> nr_slots_allocated ; i ++ ) {
271335 KVMSlot * mem = & kml -> slots [i ];
272336
273337 if (ram >= mem -> ram && ram < mem -> ram + mem -> memory_size ) {
@@ -1071,7 +1135,7 @@ static int kvm_physical_log_clear(KVMMemoryListener *kml,
10711135
10721136 kvm_slots_lock ();
10731137
1074- for (i = 0 ; i < s -> nr_slots ; i ++ ) {
1138+ for (i = 0 ; i < kml -> nr_slots_allocated ; i ++ ) {
10751139 mem = & kml -> slots [i ];
10761140 /* Discard slots that are empty or do not overlap the section */
10771141 if (!mem -> memory_size ||
@@ -1719,12 +1783,8 @@ static void kvm_log_sync_global(MemoryListener *l, bool last_stage)
17191783 /* Flush all kernel dirty addresses into KVMSlot dirty bitmap */
17201784 kvm_dirty_ring_flush ();
17211785
1722- /*
1723- * TODO: make this faster when nr_slots is big while there are
1724- * only a few used slots (small VMs).
1725- */
17261786 kvm_slots_lock ();
1727- for (i = 0 ; i < s -> nr_slots ; i ++ ) {
1787+ for (i = 0 ; i < kml -> nr_slots_allocated ; i ++ ) {
17281788 mem = & kml -> slots [i ];
17291789 if (mem -> memory_size && mem -> flags & KVM_MEM_LOG_DIRTY_PAGES ) {
17301790 kvm_slot_sync_dirty_pages (mem );
@@ -1839,12 +1899,9 @@ void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
18391899{
18401900 int i ;
18411901
1842- kml -> slots = g_new0 (KVMSlot , s -> nr_slots );
18431902 kml -> as_id = as_id ;
18441903
1845- for (i = 0 ; i < s -> nr_slots ; i ++ ) {
1846- kml -> slots [i ].slot = i ;
1847- }
1904+ kvm_slots_grow (kml , KVM_MEMSLOTS_NR_ALLOC_DEFAULT );
18481905
18491906 QSIMPLEQ_INIT (& kml -> transaction_add );
18501907 QSIMPLEQ_INIT (& kml -> transaction_del );
@@ -2603,7 +2660,7 @@ static int kvm_init(MachineState *ms)
26032660 }
26042661
26052662 kvm_readonly_mem_allowed =
2606- (kvm_check_extension (s , KVM_CAP_READONLY_MEM ) > 0 );
2663+ (kvm_vm_check_extension (s , KVM_CAP_READONLY_MEM ) > 0 );
26072664
26082665 kvm_resamplefds_allowed =
26092666 (kvm_check_extension (s , KVM_CAP_IRQFD_RESAMPLE ) > 0 );
0 commit comments