@@ -951,6 +951,117 @@ static void uffd_zeropage_test(uffd_test_args_t *args)
951
951
uffd_test_pass ();
952
952
}
953
953
954
+ static void uffd_register_poison (int uffd , void * addr , uint64_t len )
955
+ {
956
+ uint64_t ioctls = 0 ;
957
+ uint64_t expected = (1 << _UFFDIO_COPY ) | (1 << _UFFDIO_POISON );
958
+
959
+ if (uffd_register_with_ioctls (uffd , addr , len , true,
960
+ false, false, & ioctls ))
961
+ err ("poison register fail" );
962
+
963
+ if ((ioctls & expected ) != expected )
964
+ err ("registered area doesn't support COPY and POISON ioctls" );
965
+ }
966
+
967
+ static void do_uffdio_poison (int uffd , unsigned long offset )
968
+ {
969
+ struct uffdio_poison uffdio_poison = { 0 };
970
+ int ret ;
971
+ __s64 res ;
972
+
973
+ uffdio_poison .range .start = (unsigned long ) area_dst + offset ;
974
+ uffdio_poison .range .len = page_size ;
975
+ uffdio_poison .mode = 0 ;
976
+ ret = ioctl (uffd , UFFDIO_POISON , & uffdio_poison );
977
+ res = uffdio_poison .updated ;
978
+
979
+ if (ret )
980
+ err ("UFFDIO_POISON error: %" PRId64 , (int64_t )res );
981
+ else if (res != page_size )
982
+ err ("UFFDIO_POISON unexpected size: %" PRId64 , (int64_t )res );
983
+ }
984
+
985
+ static void uffd_poison_handle_fault (
986
+ struct uffd_msg * msg , struct uffd_args * args )
987
+ {
988
+ unsigned long offset ;
989
+
990
+ if (msg -> event != UFFD_EVENT_PAGEFAULT )
991
+ err ("unexpected msg event %u" , msg -> event );
992
+
993
+ if (msg -> arg .pagefault .flags &
994
+ (UFFD_PAGEFAULT_FLAG_WP | UFFD_PAGEFAULT_FLAG_MINOR ))
995
+ err ("unexpected fault type %llu" , msg -> arg .pagefault .flags );
996
+
997
+ offset = (char * )(unsigned long )msg -> arg .pagefault .address - area_dst ;
998
+ offset &= ~(page_size - 1 );
999
+
1000
+ /* Odd pages -> copy zeroed page; even pages -> poison. */
1001
+ if (offset & page_size )
1002
+ copy_page (uffd , offset , false);
1003
+ else
1004
+ do_uffdio_poison (uffd , offset );
1005
+ }
1006
+
1007
+ static void uffd_poison_test (uffd_test_args_t * targs )
1008
+ {
1009
+ pthread_t uffd_mon ;
1010
+ char c ;
1011
+ struct uffd_args args = { 0 };
1012
+ struct sigaction act = { 0 };
1013
+ unsigned long nr_sigbus = 0 ;
1014
+ unsigned long nr ;
1015
+
1016
+ fcntl (uffd , F_SETFL , uffd_flags | O_NONBLOCK );
1017
+
1018
+ uffd_register_poison (uffd , area_dst , nr_pages * page_size );
1019
+ memset (area_src , 0 , nr_pages * page_size );
1020
+
1021
+ args .handle_fault = uffd_poison_handle_fault ;
1022
+ if (pthread_create (& uffd_mon , NULL , uffd_poll_thread , & args ))
1023
+ err ("uffd_poll_thread create" );
1024
+
1025
+ sigbuf = & jbuf ;
1026
+ act .sa_sigaction = sighndl ;
1027
+ act .sa_flags = SA_SIGINFO ;
1028
+ if (sigaction (SIGBUS , & act , 0 ))
1029
+ err ("sigaction" );
1030
+
1031
+ for (nr = 0 ; nr < nr_pages ; ++ nr ) {
1032
+ unsigned long offset = nr * page_size ;
1033
+ const char * bytes = (const char * ) area_dst + offset ;
1034
+ const char * i ;
1035
+
1036
+ if (sigsetjmp (* sigbuf , 1 )) {
1037
+ /*
1038
+ * Access below triggered a SIGBUS, which was caught by
1039
+ * sighndl, which then jumped here. Count this SIGBUS,
1040
+ * and move on to next page.
1041
+ */
1042
+ ++ nr_sigbus ;
1043
+ continue ;
1044
+ }
1045
+
1046
+ for (i = bytes ; i < bytes + page_size ; ++ i ) {
1047
+ if (* i )
1048
+ err ("nonzero byte in area_dst (%p) at %p: %u" ,
1049
+ area_dst , i , * i );
1050
+ }
1051
+ }
1052
+
1053
+ if (write (pipefd [1 ], & c , sizeof (c )) != sizeof (c ))
1054
+ err ("pipe write" );
1055
+ if (pthread_join (uffd_mon , NULL ))
1056
+ err ("pthread_join()" );
1057
+
1058
+ if (nr_sigbus != nr_pages / 2 )
1059
+ err ("expected to receive %lu SIGBUS, actually received %lu" ,
1060
+ nr_pages / 2 , nr_sigbus );
1061
+
1062
+ uffd_test_pass ();
1063
+ }
1064
+
954
1065
/*
955
1066
* Test the returned uffdio_register.ioctls with different register modes.
956
1067
* Note that _UFFDIO_ZEROPAGE is tested separately in the zeropage test.
@@ -1126,6 +1237,12 @@ uffd_test_case_t uffd_tests[] = {
1126
1237
UFFD_FEATURE_PAGEFAULT_FLAG_WP |
1127
1238
UFFD_FEATURE_WP_HUGETLBFS_SHMEM ,
1128
1239
},
1240
+ {
1241
+ .name = "poison" ,
1242
+ .uffd_fn = uffd_poison_test ,
1243
+ .mem_targets = MEM_ALL ,
1244
+ .uffd_feature_required = UFFD_FEATURE_POISON ,
1245
+ },
1129
1246
};
1130
1247
1131
1248
static void usage (const char * prog )
0 commit comments