1212#include <assert.h>
1313#include <sched.h>
1414#include <sys/mman.h>
15+ #include <sys/resource.h>
1516#include <sys/types.h>
1617#include <sys/stat.h>
1718#include <unistd.h>
@@ -196,6 +197,11 @@ static void vm_open(struct kvm_vm *vm)
196197
197198 vm -> fd = __kvm_ioctl (vm -> kvm_fd , KVM_CREATE_VM , (void * )vm -> type );
198199 TEST_ASSERT (vm -> fd >= 0 , KVM_IOCTL_ERROR (KVM_CREATE_VM , vm -> fd ));
200+
201+ if (kvm_has_cap (KVM_CAP_BINARY_STATS_FD ))
202+ vm -> stats .fd = vm_get_stats_fd (vm );
203+ else
204+ vm -> stats .fd = -1 ;
199205}
200206
201207const char * vm_guest_mode_string (uint32_t i )
@@ -406,6 +412,38 @@ static uint64_t vm_nr_pages_required(enum vm_guest_mode mode,
406412 return vm_adjust_num_guest_pages (mode , nr_pages );
407413}
408414
415+ void kvm_set_files_rlimit (uint32_t nr_vcpus )
416+ {
417+ /*
418+ * Each vCPU will open two file descriptors: the vCPU itself and the
419+ * vCPU's binary stats file descriptor. Add an arbitrary amount of
420+ * buffer for all other files a test may open.
421+ */
422+ int nr_fds_wanted = nr_vcpus * 2 + 100 ;
423+ struct rlimit rl ;
424+
425+ /*
426+ * Check that we're allowed to open nr_fds_wanted file descriptors and
427+ * try raising the limits if needed.
428+ */
429+ TEST_ASSERT (!getrlimit (RLIMIT_NOFILE , & rl ), "getrlimit() failed!" );
430+
431+ if (rl .rlim_cur < nr_fds_wanted ) {
432+ rl .rlim_cur = nr_fds_wanted ;
433+ if (rl .rlim_max < nr_fds_wanted ) {
434+ int old_rlim_max = rl .rlim_max ;
435+
436+ rl .rlim_max = nr_fds_wanted ;
437+ __TEST_REQUIRE (setrlimit (RLIMIT_NOFILE , & rl ) >= 0 ,
438+ "RLIMIT_NOFILE hard limit is too low (%d, wanted %d)" ,
439+ old_rlim_max , nr_fds_wanted );
440+ } else {
441+ TEST_ASSERT (!setrlimit (RLIMIT_NOFILE , & rl ), "setrlimit() failed!" );
442+ }
443+ }
444+
445+ }
446+
409447struct kvm_vm * __vm_create (struct vm_shape shape , uint32_t nr_runnable_vcpus ,
410448 uint64_t nr_extra_pages )
411449{
@@ -415,6 +453,8 @@ struct kvm_vm *__vm_create(struct vm_shape shape, uint32_t nr_runnable_vcpus,
415453 struct kvm_vm * vm ;
416454 int i ;
417455
456+ kvm_set_files_rlimit (nr_runnable_vcpus );
457+
418458 pr_debug ("%s: mode='%s' type='%d', pages='%ld'\n" , __func__ ,
419459 vm_guest_mode_string (shape .mode ), shape .type , nr_pages );
420460
@@ -657,6 +697,23 @@ userspace_mem_region_find(struct kvm_vm *vm, uint64_t start, uint64_t end)
657697 return NULL ;
658698}
659699
700+ static void kvm_stats_release (struct kvm_binary_stats * stats )
701+ {
702+ int ret ;
703+
704+ if (stats -> fd < 0 )
705+ return ;
706+
707+ if (stats -> desc ) {
708+ free (stats -> desc );
709+ stats -> desc = NULL ;
710+ }
711+
712+ ret = close (stats -> fd );
713+ TEST_ASSERT (!ret , __KVM_SYSCALL_ERROR ("close()" , ret ));
714+ stats -> fd = -1 ;
715+ }
716+
660717__weak void vcpu_arch_free (struct kvm_vcpu * vcpu )
661718{
662719
@@ -690,6 +747,8 @@ static void vm_vcpu_rm(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
690747 ret = close (vcpu -> fd );
691748 TEST_ASSERT (!ret , __KVM_SYSCALL_ERROR ("close()" , ret ));
692749
750+ kvm_stats_release (& vcpu -> stats );
751+
693752 list_del (& vcpu -> list );
694753
695754 vcpu_arch_free (vcpu );
@@ -709,6 +768,9 @@ void kvm_vm_release(struct kvm_vm *vmp)
709768
710769 ret = close (vmp -> kvm_fd );
711770 TEST_ASSERT (!ret , __KVM_SYSCALL_ERROR ("close()" , ret ));
771+
772+ /* Free cached stats metadata and close FD */
773+ kvm_stats_release (& vmp -> stats );
712774}
713775
714776static void __vm_mem_region_delete (struct kvm_vm * vm ,
@@ -748,12 +810,6 @@ void kvm_vm_free(struct kvm_vm *vmp)
748810 if (vmp == NULL )
749811 return ;
750812
751- /* Free cached stats metadata and close FD */
752- if (vmp -> stats_fd ) {
753- free (vmp -> stats_desc );
754- close (vmp -> stats_fd );
755- }
756-
757813 /* Free userspace_mem_regions. */
758814 hash_for_each_safe (vmp -> regions .slot_hash , ctr , node , region , slot_node )
759815 __vm_mem_region_delete (vmp , region );
@@ -1286,6 +1342,11 @@ struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
12861342 TEST_ASSERT (vcpu -> run != MAP_FAILED ,
12871343 __KVM_SYSCALL_ERROR ("mmap()" , (int )(unsigned long )MAP_FAILED ));
12881344
1345+ if (kvm_has_cap (KVM_CAP_BINARY_STATS_FD ))
1346+ vcpu -> stats .fd = vcpu_get_stats_fd (vcpu );
1347+ else
1348+ vcpu -> stats .fd = -1 ;
1349+
12891350 /* Add to linked-list of VCPUs. */
12901351 list_add (& vcpu -> list , & vm -> vcpus );
12911352
@@ -2198,46 +2259,31 @@ void read_stat_data(int stats_fd, struct kvm_stats_header *header,
21982259 desc -> name , size , ret );
21992260}
22002261
2201- /*
2202- * Read the data of the named stat
2203- *
2204- * Input Args:
2205- * vm - the VM for which the stat should be read
2206- * stat_name - the name of the stat to read
2207- * max_elements - the maximum number of 8-byte values to read into data
2208- *
2209- * Output Args:
2210- * data - the buffer into which stat data should be read
2211- *
2212- * Read the data values of a specified stat from the binary stats interface.
2213- */
2214- void __vm_get_stat (struct kvm_vm * vm , const char * stat_name , uint64_t * data ,
2215- size_t max_elements )
2262+ void kvm_get_stat (struct kvm_binary_stats * stats , const char * name ,
2263+ uint64_t * data , size_t max_elements )
22162264{
22172265 struct kvm_stats_desc * desc ;
22182266 size_t size_desc ;
22192267 int i ;
22202268
2221- if (!vm -> stats_fd ) {
2222- vm -> stats_fd = vm_get_stats_fd (vm );
2223- read_stats_header (vm -> stats_fd , & vm -> stats_header );
2224- vm -> stats_desc = read_stats_descriptors (vm -> stats_fd ,
2225- & vm -> stats_header );
2269+ if (!stats -> desc ) {
2270+ read_stats_header (stats -> fd , & stats -> header );
2271+ stats -> desc = read_stats_descriptors (stats -> fd , & stats -> header );
22262272 }
22272273
2228- size_desc = get_stats_descriptor_size (& vm -> stats_header );
2274+ size_desc = get_stats_descriptor_size (& stats -> header );
22292275
2230- for (i = 0 ; i < vm -> stats_header .num_desc ; ++ i ) {
2231- desc = (void * )vm -> stats_desc + (i * size_desc );
2276+ for (i = 0 ; i < stats -> header .num_desc ; ++ i ) {
2277+ desc = (void * )stats -> desc + (i * size_desc );
22322278
2233- if (strcmp (desc -> name , stat_name ))
2279+ if (strcmp (desc -> name , name ))
22342280 continue ;
22352281
2236- read_stat_data (vm -> stats_fd , & vm -> stats_header , desc ,
2237- data , max_elements );
2238-
2239- break ;
2282+ read_stat_data (stats -> fd , & stats -> header , desc , data , max_elements );
2283+ return ;
22402284 }
2285+
2286+ TEST_FAIL ("Unable to find stat '%s'" , name );
22412287}
22422288
22432289__weak void kvm_arch_vm_post_create (struct kvm_vm * vm )
0 commit comments