Author: markj
Date: Tue Aug 27 14:06:34 2019
New Revision: 351547
URL: https://svnweb.freebsd.org/changeset/base/351547

Log:
  Fix several logic issues in domainset_empty_vm().
  
  - Don't add 1 to the result of DOMAINSET_FLS.
  - Do not modify domainsets containing only empty domains.
  - Always flatten a _PREFER policy to _ROUNDROBIN if the preferred
    domain is empty.  Previously we were doing this only when ds_cnt > 1.
  
  These bugs could cause hangs during boot if a VM domain is empty.
  
  Tested by:    hselasky
  Reviewed by:  hselasky, kib
  MFC after:    1 week
  Sponsored by: The FreeBSD Foundation
  Differential Revision:        https://reviews.freebsd.org/D21420

Modified:
  head/sys/kern/kern_cpuset.c

Modified: head/sys/kern/kern_cpuset.c
==============================================================================
--- head/sys/kern/kern_cpuset.c Tue Aug 27 14:04:32 2019        (r351546)
+++ head/sys/kern/kern_cpuset.c Tue Aug 27 14:06:34 2019        (r351547)
@@ -500,25 +500,31 @@ _domainset_create(struct domainset *domain, struct dom
 static bool
 domainset_empty_vm(struct domainset *domain)
 {
-       int i, j, max;
+       domainset_t empty;
+       int i, j;
 
-       max = DOMAINSET_FLS(&domain->ds_mask) + 1;
-       for (i = 0; i < max; i++)
-               if (DOMAINSET_ISSET(i, &domain->ds_mask) && VM_DOMAIN_EMPTY(i))
-                       DOMAINSET_CLR(i, &domain->ds_mask);
+       DOMAINSET_ZERO(&empty);
+       for (i = 0; i < vm_ndomains; i++)
+               if (VM_DOMAIN_EMPTY(i))
+                       DOMAINSET_SET(i, &empty);
+       if (DOMAINSET_SUBSET(&empty, &domain->ds_mask))
+               return (true);
+
+       /* Remove empty domains from the set and recompute. */
+       DOMAINSET_NAND(&domain->ds_mask, &empty);
        domain->ds_cnt = DOMAINSET_COUNT(&domain->ds_mask);
-       max = DOMAINSET_FLS(&domain->ds_mask) + 1;
-       for (i = j = 0; i < max; i++) {
+       for (i = j = 0; i < DOMAINSET_FLS(&domain->ds_mask); i++)
                if (DOMAINSET_ISSET(i, &domain->ds_mask))
                        domain->ds_order[j++] = i;
-               else if (domain->ds_policy == DOMAINSET_POLICY_PREFER &&
-                   domain->ds_prefer == i && domain->ds_cnt > 1) {
-                       domain->ds_policy = DOMAINSET_POLICY_ROUNDROBIN;
-                       domain->ds_prefer = -1;
-               }
+
+       /* Convert a PREFER policy referencing an empty domain to RR. */
+       if (domain->ds_policy == DOMAINSET_POLICY_PREFER &&
+           DOMAINSET_ISSET(domain->ds_prefer, &empty)) {
+               domain->ds_policy = DOMAINSET_POLICY_ROUNDROBIN;
+               domain->ds_prefer = -1;
        }
 
-       return (DOMAINSET_EMPTY(&domain->ds_mask));
+       return (false);
 }
 
 /*
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to