summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBruce Ashfield <bruce.ashfield@gmail.com>2020-08-06 15:57:25 -0400
committerRichard Purdie <richard.purdie@linuxfoundation.org>2020-08-08 09:17:49 +0100
commit24f830fc75f46f4c9e87a757713e09cf91d76a73 (patch)
tree5b410a5c59fd0a619ef0c6354098b5f045ad9775
parentbfabdcfa3786f6b7c8d4df5130f653df299d3ab6 (diff)
downloadpoky-24f830fc75f46f4c9e87a757713e09cf91d76a73.tar.gz
kernel-yocto: enhance configuration queue analysis capabilities
Enable the kernel-yocto bbclass to use enhanced capabilities from the kern-tools symbol_why.pl. We bump the kern-tools SRCREV to pickup the reworking of symbol_why, which uses Kconfiglib to provide analysis on configuration values. This is useful for debugging why a symbol specified in a fragment did not end up in the final .config. We introduce two ways to interact with the new symbol_why: 1) a replacement of the existing kconf_check script 2) a dedicated task that is explicitly invoked to dump details on the configuration. The kconf_check replacement is transparent to the user, and is run in exactly the same way as it was previously. But we get better output and more detailed diagnostics if there are symbols that don't make it into the final .config The second way to interact with symbol why is via the new task do_config_analysis. This is invoked like any other task, and by default will provide a full configuration analysis and point the user at files to look at for details. If a more targetted analysis is desired, then specific symbols can be set in the CONFIG_ANALYSIS variable. When this variable is set, the task will only run for the given symbols and provide per-variable links to the user. This variable can be set like any other, including specification in the local.conf: CONFIG_ANALYSIS_pn-linux-yocto-dev = 'NF_CONNTRACK LOCALVERSION' Which produces output as follows: WARNING: linux-yocto-dev-5.8-rc++gitAUTOINC+d22beb8f8a_8fc484ed37-r0 do_config_analysis: Configuration analysis executed, see: tmp/work/qemuarm64-poky-linux/linux-yocto-dev/5.8-rc++gitAUTOINC+d22beb8f8a_8fc484ed37-r0/NF_CONNTRACK-config-analysis.txt for details WARNING: linux-yocto-dev-5.8-rc++gitAUTOINC+d22beb8f8a_8fc484ed37-r0 do_config_analysis: Configuration audit executed, see: tmp/work/qemuarm64-poky-linux/linux-yocto-dev/5.8-rc++gitAUTOINC+d22beb8f8a_8fc484ed37-r0/NF_CONNTRACK-config-audit.txt for details WARNING: linux-yocto-dev-5.8-rc++gitAUTOINC+d22beb8f8a_8fc484ed37-r0 do_config_analysis: Configuration analysis executed, see: tmp/work/qemuarm64-poky-linux/linux-yocto-dev/5.8-rc++gitAUTOINC+d22beb8f8a_8fc484ed37-r0/LOCALVERSION-config-analysis.txt for details WARNING: linux-yocto-dev-5.8-rc++gitAUTOINC+d22beb8f8a_8fc484ed37-r0 do_config_analysis: Configuration audit executed, see: work/qemuarm64-poky-linux/linux-yocto-dev/5.8-rc++gitAUTOINC+d22beb8f8a_8fc484ed37-r0/LOCALVERSION-config-audit.txt for details (From OE-Core rev: cbc896def4c8bab3150d3405969e5dd018d62d0c) Signed-off-by: Bruce Ashfield <bruce.ashfield@gmail.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--meta/classes/kernel-yocto.bbclass159
-rw-r--r--meta/recipes-kernel/kern-tools/kern-tools-native_git.bb2
-rw-r--r--meta/recipes-kernel/linux/linux-yocto_5.4.bb2
3 files changed, 128 insertions, 35 deletions
diff --git a/meta/classes/kernel-yocto.bbclass b/meta/classes/kernel-yocto.bbclass
index 70818cc01c..77849a28c9 100644
--- a/meta/classes/kernel-yocto.bbclass
+++ b/meta/classes/kernel-yocto.bbclass
@@ -405,6 +405,67 @@ do_kernel_configme() {
405} 405}
406 406
407addtask kernel_configme before do_configure after do_patch 407addtask kernel_configme before do_configure after do_patch
408addtask config_analysis
409
410do_config_analysis[depends] = "virtual/kernel:do_configure"
411do_config_analysis[depends] += "kern-tools-native:do_populate_sysroot"
412
413CONFIG_AUDIT_FILE ?= "${WORKDIR}/config-audit.txt"
414CONFIG_ANALYSIS_FILE ?= "${WORKDIR}/config-analysis.txt"
415
416python do_config_analysis() {
417 import re, string, sys, subprocess
418
419 s = d.getVar('S')
420
421 env = os.environ.copy()
422 env['PATH'] = "%s:%s%s" % (d.getVar('PATH'), s, "/scripts/util/")
423 env['LD'] = d.getVar('KERNEL_LD')
424 env['CC'] = d.getVar('KERNEL_CC')
425 env['ARCH'] = d.getVar('ARCH')
426 env['srctree'] = s
427
428 # read specific symbols from the kernel recipe or from local.conf
429 # i.e.: CONFIG_ANALYSIS_pn-linux-yocto-dev = 'NF_CONNTRACK LOCALVERSION'
430 config = d.getVar( 'CONFIG_ANALYSIS' )
431 if not config:
432 config = [ "" ]
433 else:
434 config = config.split()
435
436 for c in config:
437 for action in ["analysis","audit"]:
438 if action == "analysis":
439 try:
440 analysis = subprocess.check_output(['symbol_why.py', '--dotconfig', '{}'.format( d.getVar('B') + '/.config' ), '--blame', c], cwd=s, env=env ).decode('utf-8')
441 except subprocess.CalledProcessError as e:
442 bb.fatal( "config analysis failed: %s" % e.output.decode('utf-8'))
443
444 outfile = d.getVar( 'CONFIG_ANALYSIS_FILE' )
445
446 if action == "audit":
447 try:
448 analysis = subprocess.check_output(['symbol_why.py', '--dotconfig', '{}'.format( d.getVar('B') + '/.config' ), '--summary', '--extended', '--sanity', c], cwd=s, env=env ).decode('utf-8')
449 except subprocess.CalledProcessError as e:
450 bb.fatal( "config analysis failed: %s" % e.output.decode('utf-8'))
451
452 outfile = d.getVar( 'CONFIG_AUDIT_FILE' )
453
454 if c:
455 outdir = os.path.dirname( outfile )
456 outname = os.path.basename( outfile )
457 outfile = outdir + '/'+ c + '-' + outname
458
459 if config and os.path.isfile(outfile):
460 os.remove(outfile)
461
462 with open(outfile, 'w+') as f:
463 f.write( analysis )
464
465 bb.warn( "Configuration {} executed, see: {} for details".format(action,outfile ))
466 if c:
467 bb.warn( analysis )
468}
408 469
409python do_kernel_configcheck() { 470python do_kernel_configcheck() {
410 import re, string, sys, subprocess 471 import re, string, sys, subprocess
@@ -414,57 +475,89 @@ python do_kernel_configcheck() {
414 # meta-series for processing 475 # meta-series for processing
415 kmeta = d.getVar("KMETA") or "meta" 476 kmeta = d.getVar("KMETA") or "meta"
416 if not os.path.exists(kmeta): 477 if not os.path.exists(kmeta):
417 kmeta = "." + kmeta 478 kmeta = subprocess.check_output(['kgit', '--meta']).decode('utf-8').rstrip()
418 479
419 s = d.getVar('S') 480 s = d.getVar('S')
420 481
421 env = os.environ.copy() 482 env = os.environ.copy()
422 env['PATH'] = "%s:%s%s" % (d.getVar('PATH'), s, "/scripts/util/") 483 env['PATH'] = "%s:%s%s" % (d.getVar('PATH'), s, "/scripts/util/")
423 env['LD'] = "${KERNEL_LD}" 484 env['LD'] = d.getVar('KERNEL_LD')
485 env['CC'] = d.getVar('KERNEL_CC')
486 env['ARCH'] = d.getVar('ARCH')
487 env['srctree'] = s
424 488
425 try: 489 try:
426 configs = subprocess.check_output(['scc', '--configs', '-o', s + '/.kernel-meta'], env=env).decode('utf-8') 490 configs = subprocess.check_output(['scc', '--configs', '-o', s + '/.kernel-meta'], env=env).decode('utf-8')
427 except subprocess.CalledProcessError as e: 491 except subprocess.CalledProcessError as e:
428 bb.fatal( "Cannot gather config fragments for audit: %s" % e.output.decode("utf-8") ) 492 bb.fatal( "Cannot gather config fragments for audit: %s" % e.output.decode("utf-8") )
429 493
430 try:
431 subprocess.check_call(['kconf_check', '--report', '-o',
432 '%s/%s/cfg' % (s, kmeta), d.getVar('B') + '/.config', s, configs], cwd=s, env=env)
433 except subprocess.CalledProcessError:
434 # The configuration gathering can return different exit codes, but
435 # we interpret them based on the KCONF_AUDIT_LEVEL variable, so we catch
436 # everything here, and let the run continue.
437 pass
438
439 config_check_visibility = int(d.getVar("KCONF_AUDIT_LEVEL") or 0) 494 config_check_visibility = int(d.getVar("KCONF_AUDIT_LEVEL") or 0)
440 bsp_check_visibility = int(d.getVar("KCONF_BSP_AUDIT_LEVEL") or 0) 495 bsp_check_visibility = int(d.getVar("KCONF_BSP_AUDIT_LEVEL") or 0)
441 496
442 # if config check visibility is non-zero, report dropped configuration values 497 # if config check visibility is "1", that's the lowest level of audit. So
443 mismatch_file = d.expand("${S}/%s/cfg/mismatch.txt" % kmeta) 498 # we add the --classify option to the run, since classification will
444 if os.path.exists(mismatch_file): 499 # streamline the output to only report options that could be boot issues,
445 if config_check_visibility: 500 # or are otherwise required for proper operation.
446 with open (mismatch_file, "r") as myfile: 501 extra_params = ""
502 if config_check_visibility == 1:
503 extra_params = "--classify"
504
505 # category #1: mismatches
506 try:
507 analysis = subprocess.check_output(['symbol_why.py', '--dotconfig', '{}'.format( d.getVar('B') + '/.config' ), '--mismatches', extra_params], cwd=s, env=env ).decode('utf-8')
508 except subprocess.CalledProcessError as e:
509 bb.fatal( "config analysis failed: %s" % e.output.decode('utf-8'))
510
511 if analysis:
512 outfile = "{}/{}/cfg/mismatch.txt".format( s, kmeta )
513 if os.path.isfile(outfile):
514 os.remove(outfile)
515 with open(outfile, 'w+') as f:
516 f.write( analysis )
517
518 if config_check_visibility and os.stat(outfile).st_size > 0:
519 with open (outfile, "r") as myfile:
447 results = myfile.read() 520 results = myfile.read()
448 bb.warn( "[kernel config]: specified values did not make it into the kernel's final configuration:\n\n%s" % results) 521 bb.warn( "[kernel config]: specified values did not make it into the kernel's final configuration:\n\n%s" % results)
449 522
450 if bsp_check_visibility: 523 # category #2: invalid fragment elements
451 invalid_file = d.expand("${S}/%s/cfg/invalid.cfg" % kmeta) 524 extra_params = ""
452 if os.path.exists(invalid_file) and os.stat(invalid_file).st_size > 0: 525 if bsp_check_visibility > 1:
453 with open (invalid_file, "r") as myfile: 526 extra_params = "--strict"
454 results = myfile.read() 527 try:
455 bb.warn( "[kernel config]: This BSP sets config options that are not offered anywhere within this kernel:\n\n%s" % results) 528 analysis = subprocess.check_output(['symbol_why.py', '--dotconfig', '{}'.format( d.getVar('B') + '/.config' ), '--invalid', extra_params], cwd=s, env=env ).decode('utf-8')
456 errors_file = d.expand("${S}/%s/cfg/fragment_errors.txt" % kmeta) 529 except subprocess.CalledProcessError as e:
457 if os.path.exists(errors_file) and os.stat(errors_file).st_size > 0: 530 bb.fatal( "config analysis failed: %s" % e.output.decode('utf-8'))
458 with open (errors_file, "r") as myfile: 531
532 if analysis:
533 outfile = "{}/{}/cfg/invalid.txt".format(s,kmeta)
534 if os.path.isfile(outfile):
535 os.remove(outfile)
536 with open(outfile, 'w+') as f:
537 f.write( analysis )
538
539 if bsp_check_visibility and os.stat(outfile).st_size > 0:
540 with open (outfile, "r") as myfile:
459 results = myfile.read() 541 results = myfile.read()
460 bb.warn( "[kernel config]: This BSP contains fragments with errors:\n\n%s" % results) 542 bb.warn( "[kernel config]: This BSP contains fragments with warnings:\n\n%s" % results)
461 543
462 # if the audit level is greater than two, we report if a fragment has overriden 544 # category #3: redefined options (this is pretty verbose and is debug only)
463 # a value from a base fragment. This is really only used for new kernel introduction 545 try:
464 if bsp_check_visibility > 2: 546 analysis = subprocess.check_output(['symbol_why.py', '--dotconfig', '{}'.format( d.getVar('B') + '/.config' ), '--sanity'], cwd=s, env=env ).decode('utf-8')
465 redefinition_file = d.expand("${S}/%s/cfg/redefinition.txt" % kmeta) 547 except subprocess.CalledProcessError as e:
466 if os.path.exists(redefinition_file) and os.stat(redefinition_file).st_size > 0: 548 bb.fatal( "config analysis failed: %s" % e.output.decode('utf-8'))
467 with open (redefinition_file, "r") as myfile: 549
550 if analysis:
551 outfile = "{}/{}/cfg/redefinition.txt".format(s,kmeta)
552 if os.path.isfile(outfile):
553 os.remove(outfile)
554 with open(outfile, 'w+') as f:
555 f.write( analysis )
556
557 # if the audit level is greater than two, we report if a fragment has overriden
558 # a value from a base fragment. This is really only used for new kernel introduction
559 if bsp_check_visibility > 2 and os.stat(outfile).st_size > 0:
560 with open (outfile, "r") as myfile:
468 results = myfile.read() 561 results = myfile.read()
469 bb.warn( "[kernel config]: This BSP has configuration options defined in more than one config, with differing values:\n\n%s" % results) 562 bb.warn( "[kernel config]: This BSP has configuration options defined in more than one config, with differing values:\n\n%s" % results)
470} 563}
diff --git a/meta/recipes-kernel/kern-tools/kern-tools-native_git.bb b/meta/recipes-kernel/kern-tools/kern-tools-native_git.bb
index 4f1af731d6..4402e14754 100644
--- a/meta/recipes-kernel/kern-tools/kern-tools-native_git.bb
+++ b/meta/recipes-kernel/kern-tools/kern-tools-native_git.bb
@@ -4,7 +4,7 @@ LIC_FILES_CHKSUM = "file://tools/kgit;beginline=5;endline=9;md5=9c30e971d435e249
4 4
5DEPENDS = "git-native" 5DEPENDS = "git-native"
6 6
7SRCREV = "c66833e1caac25279a5052fceb13213f5e4f79f9" 7SRCREV = "8b6fa727013daba5e8d72e5fc61d80caed944c6a"
8PR = "r12" 8PR = "r12"
9PV = "0.2+git${SRCPV}" 9PV = "0.2+git${SRCPV}"
10 10
diff --git a/meta/recipes-kernel/linux/linux-yocto_5.4.bb b/meta/recipes-kernel/linux/linux-yocto_5.4.bb
index 3829748269..556eaa6b89 100644
--- a/meta/recipes-kernel/linux/linux-yocto_5.4.bb
+++ b/meta/recipes-kernel/linux/linux-yocto_5.4.bb
@@ -38,7 +38,7 @@ DEPENDS += "openssl-native util-linux-native"
38PV = "${LINUX_VERSION}+git${SRCPV}" 38PV = "${LINUX_VERSION}+git${SRCPV}"
39 39
40KMETA = "kernel-meta" 40KMETA = "kernel-meta"
41KCONF_BSP_AUDIT_LEVEL = "2" 41KCONF_BSP_AUDIT_LEVEL = "1"
42 42
43KERNEL_DEVICETREE_qemuarmv5 = "versatile-pb.dtb" 43KERNEL_DEVICETREE_qemuarmv5 = "versatile-pb.dtb"
44 44