colibri_imx6: fix video stdout in default environment
[oweals/u-boot.git] / scripts / checkpatch.pl
index 4142f5c837e21bd912b0770e68cc427c308dec16..edba36565167b38bffbe2e1f0a09df60b7deb3e9 100755 (executable)
@@ -1,9 +1,11 @@
 #!/usr/bin/env perl
+# SPDX-License-Identifier: GPL-2.0
+#
 # (c) 2001, Dave Jones. (the file handling bit)
 # (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit)
 # (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite)
 # (c) 2008-2010 Andy Whitcroft <apw@canonical.com>
-# Licensed under the terms of the GNU GPL License version 2
+# (c) 2010-2018 Joe Perches <joe@perches.com>
 
 use strict;
 use warnings;
@@ -11,6 +13,7 @@ use POSIX;
 use File::Basename;
 use Cwd 'abs_path';
 use Term::ANSIColor qw(:constants);
+use Encode qw(decode encode);
 
 my $P = $0;
 my $D = dirname(abs_path($P));
@@ -48,7 +51,7 @@ my %ignore_type = ();
 my @ignore = ();
 my $help = 0;
 my $configuration_file = ".checkpatch.conf";
-my $max_line_length = 80;
+my $max_line_length = 100;
 my $ignore_perl_version = 0;
 my $minimum_perl_version = 5.10.0;
 my $min_conf_desc_length = 4;
@@ -57,6 +60,7 @@ my $codespell = 0;
 my $codespellfile = "/usr/share/codespell/dictionary.txt";
 my $conststructsfile = "$D/const_structs.checkpatch";
 my $typedefsfile = "";
+my $u_boot = 0;
 my $color = "auto";
 my $allow_c99_comments = 1;
 
@@ -91,7 +95,9 @@ Options:
   --types TYPE(,TYPE2...)    show only these comma separated message types
   --ignore TYPE(,TYPE2...)   ignore various comma separated message types
   --show-types               show the specific message type in the output
-  --max-line-length=n        set the maximum line length, if exceeded, warn
+  --max-line-length=n        set the maximum line length, (default $max_line_length)
+                             if exceeded, warn on patches
+                             requires --strict for use with --file
   --min-conf-desc-length=n   set the min description length, if shorter, warn
   --root=PATH                PATH to the kernel tree root
   --no-summary               suppress the per-file summary
@@ -118,6 +124,7 @@ Options:
   --typedefsfile             Read additional types from this file
   --color[=WHEN]             Use colors 'always', 'never', or only when output
                              is a terminal ('auto'). Default is 'auto'.
+  --u-boot                   Run additional checks for U-Boot
   -h, --help, --version      display this help and exit
 
 When FILE is - read standard input.
@@ -145,7 +152,8 @@ sub list_types {
        close($script);
 
        my @types = ();
-       for ($text =~ /\b(?:(?:CHK|WARN|ERROR)\s*\(\s*"([^"]+)")/g) {
+       # Also catch when type or level is passed through a variable
+       for ($text =~ /(?:(?:\bCHK|\bWARN|\bERROR|&\{\$msg_level})\s*\(|\$msg_type\s*=)\s*"([^"]+)"/g) {
                push (@types, $_);
        }
        @types = sort(uniq(@types));
@@ -221,6 +229,7 @@ GetOptions(
        'codespell!'    => \$codespell,
        'codespellfile=s'       => \$codespellfile,
        'typedefsfile=s'        => \$typedefsfile,
+       'u-boot'        => \$u_boot,
        'color=s'       => \$color,
        'no-color'      => \$color,     #keep old behaviors of -nocolor
        'nocolor'       => \$color,     #keep old behaviors of -nocolor
@@ -237,11 +246,11 @@ $check_orig = $check;
 
 my $exit = 0;
 
+my $perl_version_ok = 1;
 if ($^V && $^V lt $minimum_perl_version) {
+       $perl_version_ok = 0;
        printf "$P: requires at least perl version %vd\n", $minimum_perl_version;
-       if (!$ignore_perl_version) {
-               exit(1);
-       }
+       exit(1) if (!$ignore_perl_version);
 }
 
 #if no filenames are given, push '-' to read patch from stdin
@@ -343,9 +352,10 @@ our $Sparse        = qr{
                        __force|
                        __iomem|
                        __must_check|
-                       __init_refok|
                        __kprobes|
                        __ref|
+                       __refconst|
+                       __refdata|
                        __rcu|
                        __private
                }x;
@@ -375,6 +385,7 @@ our $Attribute      = qr{
                        __noclone|
                        __deprecated|
                        __read_mostly|
+                       __ro_after_init|
                        __kprobes|
                        $InitAttribute|
                        ____cacheline_aligned|
@@ -453,8 +464,11 @@ our $zero_initializer = qr{(?:(?:0[xX])?0+$Int_type?|NULL|false)\b};
 our $logFunctions = qr{(?x:
        printk(?:_ratelimited|_once|_deferred_once|_deferred|)|
        (?:[a-z0-9]+_){1,2}(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)|
+       TP_printk|
        WARN(?:_RATELIMIT|_ONCE|)|
        panic|
+       debug|
+       printf|
        MODULE_[A-Z_]+|
        seq_vprintf|seq_printf|seq_puts
 )};
@@ -564,6 +578,7 @@ foreach my $entry (@mode_permission_funcs) {
        $mode_perms_search .= '|' if ($mode_perms_search ne "");
        $mode_perms_search .= $entry->[0];
 }
+$mode_perms_search = "(?:${mode_perms_search})";
 
 our $mode_perms_world_writable = qr{
        S_IWUGO         |
@@ -598,6 +613,37 @@ foreach my $entry (keys %mode_permission_string_types) {
        $mode_perms_string_search .= '|' if ($mode_perms_string_search ne "");
        $mode_perms_string_search .= $entry;
 }
+our $single_mode_perms_string_search = "(?:${mode_perms_string_search})";
+our $multi_mode_perms_string_search = qr{
+       ${single_mode_perms_string_search}
+       (?:\s*\|\s*${single_mode_perms_string_search})*
+}x;
+
+sub perms_to_octal {
+       my ($string) = @_;
+
+       return trim($string) if ($string =~ /^\s*0[0-7]{3,3}\s*$/);
+
+       my $val = "";
+       my $oval = "";
+       my $to = 0;
+       my $curpos = 0;
+       my $lastpos = 0;
+       while ($string =~ /\b(($single_mode_perms_string_search)\b(?:\s*\|\s*)?\s*)/g) {
+               $curpos = pos($string);
+               my $match = $2;
+               my $omatch = $1;
+               last if ($lastpos > 0 && ($curpos - length($omatch) != $lastpos));
+               $lastpos = $curpos;
+               $to |= $mode_permission_string_types{$match};
+               $val .= '\s*\|\s*' if ($val ne "");
+               $val .= $match;
+               $oval .= $omatch;
+       }
+       $oval =~ s/^\s*\|\s*//;
+       $oval =~ s/\s*\|\s*$//;
+       return sprintf("%04o", $to);
+}
 
 our $allowed_asm_includes = qr{(?x:
        irq|
@@ -757,7 +803,8 @@ our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant|$String)};
 our $declaration_macros = qr{(?x:
        (?:$Storage\s+)?(?:[A-Z_][A-Z0-9]*_){0,2}(?:DEFINE|DECLARE)(?:_[A-Z0-9]+){1,6}\s*\(|
        (?:$Storage\s+)?[HLP]?LIST_HEAD\s*\(|
-       (?:$Storage\s+)?${Type}\s+uninitialized_var\s*\(
+       (?:$Storage\s+)?${Type}\s+uninitialized_var\s*\(|
+       (?:SKCIPHER_REQUEST|SHASH_DESC|AHASH_REQUEST)_ON_STACK\s*\(
 )};
 
 sub deparenthesize {
@@ -810,6 +857,17 @@ sub is_maintained_obsolete {
        return $status =~ /obsolete/i;
 }
 
+sub is_SPDX_License_valid {
+       my ($license) = @_;
+
+       return 1 if (!$tree || which("python") eq "" || !(-e "$root/scripts/spdxcheck.py") || !(-e "$root/.git"));
+
+       my $root_path = abs_path($root);
+       my $status = `cd "$root_path"; echo "$license" | python scripts/spdxcheck.py -`;
+       return 0 if ($status ne "");
+       return 1;
+}
+
 my $camelcase_seeded = 0;
 sub seed_camelcase_includes {
        return if ($camelcase_seeded);
@@ -989,11 +1047,11 @@ if (!$quiet) {
        hash_show_words(\%use_type, "Used");
        hash_show_words(\%ignore_type, "Ignored");
 
-       if ($^V lt 5.10.0) {
+       if (!$perl_version_ok) {
                print << "EOM"
 
 NOTE: perl $^V is not modern enough to detect all possible issues.
-      An upgrade to at least perl v5.10.0 is suggested.
+      An upgrade to at least perl $minimum_perl_version is suggested.
 EOM
        }
        if ($exit) {
@@ -1041,7 +1099,7 @@ sub parse_email {
        } elsif ($formatted_email =~ /(\S+\@\S+)(.*)$/) {
                $address = $1;
                $comment = $2 if defined $2;
-               $formatted_email =~ s/$address.*$//;
+               $formatted_email =~ s/\Q$address\E.*$//;
                $name = $formatted_email;
                $name = trim($name);
                $name =~ s/^\"|\"$//g;
@@ -1183,7 +1241,7 @@ sub sanitise_line {
        for ($off = 1; $off < length($line); $off++) {
                $c = substr($line, $off, 1);
 
-               # Comments we are wacking completly including the begin
+               # Comments we are whacking completely including the begin
                # and end, all to $;.
                if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') {
                        $sanitise_quote = '*/';
@@ -1263,6 +1321,7 @@ sub sanitise_line {
 sub get_quoted_string {
        my ($line, $rawline) = @_;
 
+       return "" if (!defined($line) || !defined($rawline));
        return "" if ($line !~ m/($String)/g);
        return substr($rawline, $-[0], $+[0] - $-[0]);
 }
@@ -1610,6 +1669,28 @@ sub raw_line {
        return $line;
 }
 
+sub get_stat_real {
+       my ($linenr, $lc) = @_;
+
+       my $stat_real = raw_line($linenr, 0);
+       for (my $count = $linenr + 1; $count <= $lc; $count++) {
+               $stat_real = $stat_real . "\n" . raw_line($count, 0);
+       }
+
+       return $stat_real;
+}
+
+sub get_stat_here {
+       my ($linenr, $cnt, $here) = @_;
+
+       my $herectx = $here . "\n";
+       for (my $n = 0; $n < $cnt; $n++) {
+               $herectx .= raw_line($linenr, $n) . "\n";
+       }
+
+       return $herectx;
+}
+
 sub cat_vet {
        my ($vet) = @_;
        my ($res, $coded);
@@ -2159,6 +2240,41 @@ sub pos_last_openparen {
        return length(expand_tabs(substr($line, 0, $last_openparen))) + 1;
 }
 
+# Checks specific to U-Boot
+sub u_boot_line {
+       my ($realfile, $line,  $herecurr) = @_;
+
+       # ask for a test if a new uclass ID is added
+       if ($realfile =~ /uclass-id.h/ && $line =~ /^\+/) {
+               WARN("NEW_UCLASS",
+                    "Possible new uclass - make sure to add a sandbox driver, plus a test in test/dm/<name>.c\n" . $herecurr);
+       }
+
+       # try to get people to use the livetree API
+       if ($line =~ /^\+.*fdtdec_/) {
+               WARN("LIVETREE",
+                    "Use the livetree API (dev_read_...)\n" . $herecurr);
+       }
+
+       # add tests for new commands
+       if ($line =~ /^\+.*do_($Ident)\(struct cmd_tbl.*/) {
+               WARN("CMD_TEST",
+                    "Possible new command - make sure you add a test\n" . $herecurr);
+       }
+
+       # use if instead of #if
+       if ($line =~ /^\+#if.*CONFIG.*/) {
+               WARN("PREFER_IF",
+                    "Use 'if (IS_ENABLED(CONFIG...))' instead of '#if or #ifdef' where possible\n" . $herecurr);
+       }
+
+       # use defconfig to manage CONFIG_CMD options
+       if ($line =~ /\+\s*#\s*(define|undef)\s+(CONFIG_CMD\w*)\b/) {
+               ERROR("DEFINE_CONFIG_CMD",
+                     "All commands are managed by Kconfig\n" . $herecurr);
+       }
+}
+
 sub process {
        my $filename = shift;
 
@@ -2175,10 +2291,14 @@ sub process {
 
        our $clean = 1;
        my $signoff = 0;
+       my $author = '';
+       my $authorsignoff = 0;
        my $is_patch = 0;
+       my $is_binding_patch = -1;
        my $in_header_lines = $file ? 0 : 1;
        my $in_commit_log = 0;          #Scanning lines before patch
        my $has_commit_log = 0;         #Encountered lines before patch
+       my $commit_log_lines = 0;       #Number of commit log lines
        my $commit_log_possible_stack_dump = 0;
        my $commit_log_long_line = 0;
        my $commit_log_has_diff = 0;
@@ -2223,6 +2343,8 @@ sub process {
 
        my $camelcase_file_seeded = 0;
 
+       my $checklicenseline = 1;
+
        sanitise_line_reset();
        my $line;
        foreach my $rawline (@rawlines) {
@@ -2315,6 +2437,14 @@ sub process {
 
                my $rawline = $rawlines[$linenr - 1];
 
+# check if it's a mode change, rename or start of a patch
+               if (!$in_commit_log &&
+                   ($line =~ /^ mode change [0-7]+ => [0-7]+ \S+\s*$/ ||
+                   ($line =~ /^rename (?:from|to) \S+\s*$/ ||
+                    $line =~ /^diff --git a\/[\w\/\.\_\-]+ b\/\S+\s*$/))) {
+                       $is_patch = 1;
+               }
+
 #extract the line range in the file after the patch is applied
                if (!$in_commit_log &&
                    $line =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@(.*)/) {
@@ -2414,6 +2544,20 @@ sub process {
                        } else {
                                $check = $check_orig;
                        }
+                       $checklicenseline = 1;
+
+                       if ($realfile !~ /^MAINTAINERS/) {
+                               my $last_binding_patch = $is_binding_patch;
+
+                               $is_binding_patch = () = $realfile =~ m@^(?:Documentation/devicetree/|include/dt-bindings/)@;
+
+                               if (($last_binding_patch != -1) &&
+                                   ($last_binding_patch ^ $is_binding_patch)) {
+                                       WARN("DT_SPLIT_BINDING_PATCH",
+                                            "DT binding docs and includes should be a separate patch. See: Documentation/devicetree/bindings/submitting-patches.txt\n");
+                               }
+                       }
+
                        next;
                }
 
@@ -2425,6 +2569,18 @@ sub process {
 
                $cnt_lines++ if ($realcnt != 0);
 
+# Verify the existence of a commit log if appropriate
+# 2 is used because a $signature is counted in $commit_log_lines
+               if ($in_commit_log) {
+                       if ($line !~ /^\s*$/) {
+                               $commit_log_lines++;    #could be a $signature
+                       }
+               } elsif ($has_commit_log && $commit_log_lines < 2) {
+                       WARN("COMMIT_MESSAGE",
+                            "Missing commit description - Add an appropriate one\n");
+                       $commit_log_lines = 2;  #warn only once
+               }
+
 # Check if the commit log has what seems like a diff which can confuse patch
                if ($in_commit_log && !$commit_log_has_diff &&
                    (($line =~ m@^\s+diff\b.*a/[\w/]+@ &&
@@ -2446,10 +2602,24 @@ sub process {
                        }
                }
 
+# Check the patch for a From:
+               if (decode("MIME-Header", $line) =~ /^From:\s*(.*)/) {
+                       $author = $1;
+                       $author = encode("utf8", $author) if ($line =~ /=\?utf-8\?/i);
+                       $author =~ s/"//g;
+               }
+
 # Check the patch for a signoff:
                if ($line =~ /^\s*signed-off-by:/i) {
                        $signoff++;
                        $in_commit_log = 0;
+                       if ($author ne '') {
+                               my $l = $line;
+                               $l =~ s/"//g;
+                               if ($l =~ /^\s*signed-off-by:\s*\Q$author\E/i) {
+                                   $authorsignoff = 1;
+                               }
+                       }
                }
 
 # Check if MAINTAINERS is being updated.  If so, there's probably no need to
@@ -2535,12 +2705,6 @@ sub process {
                             "A patch subject line should describe the change not the tool that found it\n" . $herecurr);
                }
 
-# Check for old stable address
-               if ($line =~ /^\s*cc:\s*.*<?\bstable\@kernel\.org\b>?.*$/i) {
-                       ERROR("STABLE_ADDRESS",
-                             "The 'stable' address should be 'stable\@vger.kernel.org'\n" . $herecurr);
-               }
-
 # Check for unwanted Gerrit info
                if ($in_commit_log && $line =~ /^\s*change-id:/i) {
                        ERROR("GERRIT_CHANGE_ID",
@@ -2715,10 +2879,10 @@ sub process {
                                my $typo_fix = $spelling_fix{lc($typo)};
                                $typo_fix = ucfirst($typo_fix) if ($typo =~ /^[A-Z]/);
                                $typo_fix = uc($typo_fix) if ($typo =~ /^[A-Z]+$/);
-                               my $msg_type = \&WARN;
-                               $msg_type = \&CHK if ($file);
-                               if (&{$msg_type}("TYPO_SPELLING",
-                                                "'$typo' may be misspelled - perhaps '$typo_fix'?\n" . $herecurr) &&
+                               my $msg_level = \&WARN;
+                               $msg_level = \&CHK if ($file);
+                               if (&{$msg_level}("TYPO_SPELLING",
+                                                 "'$typo' may be misspelled - perhaps '$typo_fix'?\n" . $herecurr) &&
                                    $fix) {
                                        $fixed[$fixlinenr] =~ s/(^|[^A-Za-z@])($typo)($|[^A-Za-z@])/$1$typo_fix$3/;
                                }
@@ -2753,17 +2917,20 @@ sub process {
                    $rawline =~ /\b59\s+Temple\s+Pl/i ||
                    $rawline =~ /\b51\s+Franklin\s+St/i) {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
-                       my $msg_type = \&ERROR;
-                       $msg_type = \&CHK if ($file);
-                       &{$msg_type}("FSF_MAILING_ADDRESS",
-                                    "Do not include the paragraph about writing to the Free Software Foundation's mailing address from the sample GPL notice. The FSF has changed addresses in the past, and may do so again. Linux already includes a copy of the GPL.\n" . $herevet)
+                       my $msg_level = \&ERROR;
+                       $msg_level = \&CHK if ($file);
+                       &{$msg_level}("FSF_MAILING_ADDRESS",
+                                     "Do not include the paragraph about writing to the Free Software Foundation's mailing address from the sample GPL notice. The FSF has changed addresses in the past, and may do so again. Linux already includes a copy of the GPL.\n" . $herevet)
                }
 
 # check for Kconfig help text having a real description
 # Only applies when adding the entry originally, after that we do not have
 # sufficient context to determine whether it is indeed long enough.
                if ($realfile =~ /Kconfig/ &&
-                   $line =~ /^\+\s*config\s+/) {
+                   # 'choice' is usually the last thing on the line (though
+                   # Kconfig supports named choices), so use a word boundary
+                   # (\b) rather than a whitespace character (\s)
+                   $line =~ /^\+\s*(?:config|menuconfig|choice)\b/) {
                        my $length = 0;
                        my $cnt = $realcnt;
                        my $ln = $linenr + 1;
@@ -2778,9 +2945,13 @@ sub process {
                                next if ($f =~ /^-/);
                                last if (!$file && $f =~ /^\@\@/);
 
-                               if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate)\s*\"/) {
+                               if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) {
                                        $is_start = 1;
-                               } elsif ($lines[$ln - 1] =~ /^\+\s*(?:---)?help(?:---)?$/) {
+                               } elsif ($lines[$ln - 1] =~ /^\+\s*(?:help|---help---)\s*$/) {
+                                       if ($lines[$ln - 1] =~ "---help---") {
+                                               WARN("CONFIG_DESCRIPTION",
+                                                    "prefer 'help' over '---help---' for new help texts\n" . $herecurr);
+                                       }
                                        $length = -1;
                                }
 
@@ -2788,7 +2959,13 @@ sub process {
                                $f =~ s/#.*//;
                                $f =~ s/^\s+//;
                                next if ($f =~ /^$/);
-                               if ($f =~ /^\s*config\s/) {
+
+                               # This only checks context lines in the patch
+                               # and so hopefully shouldn't trigger false
+                               # positives, even though some of these are
+                               # common words in help texts
+                               if ($f =~ /^\s*(?:config|menuconfig|choice|endchoice|
+                                                 if|endif|menu|endmenu|source)\b/x) {
                                        $is_end = 1;
                                        last;
                                }
@@ -2864,6 +3041,36 @@ sub process {
                        }
                }
 
+# check for using SPDX license tag at beginning of files
+               if ($realline == $checklicenseline) {
+                       if ($rawline =~ /^[ \+]\s*\#\!\s*\//) {
+                               $checklicenseline = 2;
+                       } elsif ($rawline =~ /^\+/) {
+                               my $comment = "";
+                               if ($realfile =~ /\.(h|s|S)$/) {
+                                       $comment = '/*';
+                               } elsif ($realfile =~ /\.(c|dts|dtsi)$/) {
+                                       $comment = '//';
+                               } elsif (($checklicenseline == 2) || $realfile =~ /\.(sh|pl|py|awk|tc)$/) {
+                                       $comment = '#';
+                               } elsif ($realfile =~ /\.rst$/) {
+                                       $comment = '..';
+                               }
+
+                               if ($comment !~ /^$/ &&
+                                   $rawline !~ /^\+\Q$comment\E SPDX-License-Identifier: /) {
+                                        WARN("SPDX_LICENSE_TAG",
+                                             "Missing or malformed SPDX-License-Identifier tag in line $checklicenseline\n" . $herecurr);
+                               } elsif ($rawline =~ /(SPDX-License-Identifier: .*)/) {
+                                        my $spdx_license = $1;
+                                        if (!is_SPDX_License_valid($spdx_license)) {
+                                                 WARN("SPDX_LICENSE_TAG",
+                                                      "'$spdx_license' is not supported in LICENSES/...\n" . $herecurr);
+                                        }
+                               }
+                       }
+               }
+
 # check we are in a valid source file if not then ignore this hunk
                next if ($realfile !~ /\.(h|c|s|S|sh|dtsi|dts)$/);
 
@@ -2873,9 +3080,10 @@ sub process {
 #      logging functions like pr_info that end in a string
 #      lines with a single string
 #      #defines that are a single string
+#      lines with an RFC3986 like URL
 #
 # There are 3 different line length message types:
-# LONG_LINE_COMMENT    a comment starts before but extends beyond $max_linelength
+# LONG_LINE_COMMENT    a comment starts before but extends beyond $max_line_length
 # LONG_LINE_STRING     a string starts before but extends beyond $max_line_length
 # LONG_LINE            all other lines longer than $max_line_length
 #
@@ -2899,8 +3107,13 @@ sub process {
                                 $line =~ /^\+\s*#\s*define\s+\w+\s+$String$/) {
                                $msg_type = "";
 
-                       # EFI_GUID is another special case
-                       } elsif ($line =~ /^\+.*\bEFI_GUID\s*\(/) {
+                       # More special cases
+                       } elsif ($line =~ /^\+.*\bEFI_GUID\s*\(/ ||
+                                $line =~ /^\+\s*(?:\w+)?\s*DEFINE_PER_CPU/) {
+                               $msg_type = "";
+
+                       # URL ($rawline is used in case the URL is in a comment)
+                       } elsif ($rawline =~ /^\+.*\b[a-z][\w\.\+\-]*:\/\/\S+/i) {
                                $msg_type = "";
 
                        # Otherwise set the alternate message types
@@ -2918,8 +3131,10 @@ sub process {
 
                        if ($msg_type ne "" &&
                            (show_type("LONG_LINE") || show_type($msg_type))) {
-                               WARN($msg_type,
-                                    "line over $max_line_length characters\n" . $herecurr);
+                               my $msg_level = \&WARN;
+                               $msg_level = \&CHK if ($file);
+                               &{$msg_level}($msg_type,
+                                             "line length of $length exceeds $max_line_length columns\n" . $herecurr);
                        }
                }
 
@@ -2929,18 +3144,8 @@ sub process {
                             "adding a line without newline at end of file\n" . $herecurr);
                }
 
-# Blackfin: use hi/lo macros
-               if ($realfile =~ m@arch/blackfin/.*\.S$@) {
-                       if ($line =~ /\.[lL][[:space:]]*=.*&[[:space:]]*0x[fF][fF][fF][fF]/) {
-                               my $herevet = "$here\n" . cat_vet($line) . "\n";
-                               ERROR("LO_MACRO",
-                                     "use the LO() macro, not (... & 0xFFFF)\n" . $herevet);
-                       }
-                       if ($line =~ /\.[hH][[:space:]]*=.*>>[[:space:]]*16/) {
-                               my $herevet = "$here\n" . cat_vet($line) . "\n";
-                               ERROR("HI_MACRO",
-                                     "use the HI() macro, not (... >> 16)\n" . $herevet);
-                       }
+               if ($u_boot) {
+                       u_boot_line($realfile, $line,  $herecurr);
                }
 
 # check we are in a valid source file C or perl if not then ignore this hunk
@@ -2972,6 +3177,12 @@ sub process {
                        }
                }
 
+# check for assignments on the start of a line
+               if ($sline =~ /^\+\s+($Assignment)[^=]/) {
+                       CHK("ASSIGNMENT_CONTINUATIONS",
+                           "Assignment operator '$1' should be on the previous line\n" . $hereprev);
+               }
+
 # check for && or || at the start of a line
                if ($rawline =~ /^\+\s*(&&|\|\|)/) {
                        CHK("LOGICAL_CONTINUATIONS",
@@ -2979,8 +3190,8 @@ sub process {
                }
 
 # check indentation starts on a tab stop
-               if ($^V && $^V ge 5.10.0 &&
-                   $sline =~ /^\+\t+( +)(?:$c90_Keywords\b|\{\s*$|\}\s*(?:else\b|while\b|\s*$))/) {
+               if ($perl_version_ok &&
+                   $sline =~ /^\+\t+( +)(?:$c90_Keywords\b|\{\s*$|\}\s*(?:else\b|while\b|\s*$)|$Declare\s*$Ident\s*[;=])/) {
                        my $indent = length($1);
                        if ($indent % 8) {
                                if (WARN("TABSTOP",
@@ -2992,7 +3203,7 @@ sub process {
                }
 
 # check multi-line statement indentation matches previous line
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    $prevline =~ /^\+([ \t]*)((?:$c90_Keywords(?:\s+if)\s*)|(?:$Declare\s*)?(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*|(?:\*\s*)*$Lval\s*=\s*$Ident\s*)\(.*(\&\&|\|\||,)\s*$/) {
                        $prevline =~ /^\+(\t*)(.*)$/;
                        my $oldindent = $1;
@@ -3102,6 +3313,7 @@ sub process {
                      $line =~ /^\+[a-z_]*init/ ||
                      $line =~ /^\+\s*(?:static\s+)?[A-Z_]*ATTR/ ||
                      $line =~ /^\+\s*DECLARE/ ||
+                     $line =~ /^\+\s*builtin_[\w_]*driver/ ||
                      $line =~ /^\+\s*__setup/)) {
                        if (CHK("LINE_SPACING",
                                "Please use a blank line after function/struct/union/enum declarations\n" . $hereprev) &&
@@ -3148,7 +3360,7 @@ sub process {
                        # known declaration macros
                      $sline =~ /^\+\s+$declaration_macros/ ||
                        # start of struct or union or enum
-                     $sline =~ /^\+\s+(?:union|struct|enum|typedef)\b/ ||
+                     $sline =~ /^\+\s+(?:static\s+)?(?:const\s+)?(?:union|struct|enum|typedef)\b/ ||
                        # start or end of block or continuation of declaration
                      $sline =~ /^\+\s+(?:$|[\{\}\.\#\"\?\:\(\[])/ ||
                        # bitfield continuation
@@ -3181,6 +3393,12 @@ sub process {
 # check we are in a valid C source file if not then ignore this hunk
                next if ($realfile !~ /\.(h|c)$/);
 
+# check for unusual line ending [ or (
+               if ($line =~ /^\+.*([\[\(])\s*$/) {
+                       CHK("OPEN_ENDED_LINE",
+                           "Lines should not end with a '$1'\n" . $herecurr);
+               }
+
 # check if this appears to be the start function declaration, save the name
                if ($sline =~ /^\+\{\s*$/ &&
                    $prevline =~ /^\+(?:(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*)?($Ident)\(/) {
@@ -3222,18 +3440,6 @@ sub process {
                             "CVS style keyword markers, these will _not_ be updated\n". $herecurr);
                }
 
-# Blackfin: don't use __builtin_bfin_[cs]sync
-               if ($line =~ /__builtin_bfin_csync/) {
-                       my $herevet = "$here\n" . cat_vet($line) . "\n";
-                       ERROR("CSYNC",
-                             "use the CSYNC() macro in asm/blackfin.h\n" . $herevet);
-               }
-               if ($line =~ /__builtin_bfin_ssync/) {
-                       my $herevet = "$here\n" . cat_vet($line) . "\n";
-                       ERROR("SSYNC",
-                             "use the SSYNC() macro in asm/blackfin.h\n" . $herevet);
-               }
-
 # check for old HOTPLUG __dev<foo> section markings
                if ($line =~ /\b(__dev(init|exit)(data|const|))\b/) {
                        WARN("HOTPLUG_SECTION",
@@ -3686,6 +3892,26 @@ sub process {
                             "type '$tmp' should be specified in [[un]signed] [short|int|long|long long] order\n" . $herecurr);
                }
 
+# check for unnecessary <signed> int declarations of short/long/long long
+               while ($sline =~ m{\b($TypeMisordered(\s*\*)*|$C90_int_types)\b}g) {
+                       my $type = trim($1);
+                       next if ($type !~ /\bint\b/);
+                       next if ($type !~ /\b(?:short|long\s+long|long)\b/);
+                       my $new_type = $type;
+                       $new_type =~ s/\b\s*int\s*\b/ /;
+                       $new_type =~ s/\b\s*(?:un)?signed\b\s*/ /;
+                       $new_type =~ s/^const\s+//;
+                       $new_type = "unsigned $new_type" if ($type =~ /\bunsigned\b/);
+                       $new_type = "const $new_type" if ($type =~ /^const\b/);
+                       $new_type =~ s/\s+/ /g;
+                       $new_type = trim($new_type);
+                       if (WARN("UNNECESSARY_INT",
+                                "Prefer '$new_type' over '$type' as the int is unnecessary\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$fixlinenr] =~ s/\b\Q$type\E\b/$new_type/;
+                       }
+               }
+
 # check for static const char * arrays.
                if ($line =~ /\bstatic\s+const\s+char\s*\*\s*(\w+)\s*\[\s*\]\s*=\s*/) {
                        WARN("STATIC_CONST_CHAR_ARRAY",
@@ -3810,10 +4036,10 @@ sub process {
 
 # avoid BUG() or BUG_ON()
                if ($line =~ /\b(?:BUG|BUG_ON)\b/) {
-                       my $msg_type = \&WARN;
-                       $msg_type = \&CHK if ($file);
-                       &{$msg_type}("AVOID_BUG",
-                                    "Avoid crashing the kernel - try using WARN_ON & recovery code rather than BUG() or BUG_ON()\n" . $herecurr);
+                       my $msg_level = \&WARN;
+                       $msg_level = \&CHK if ($file);
+                       &{$msg_level}("AVOID_BUG",
+                                     "Avoid crashing the kernel - try using WARN_ON & recovery code rather than BUG() or BUG_ON()\n" . $herecurr);
                }
 
 # avoid LINUX_VERSION_CODE
@@ -3828,28 +4054,10 @@ sub process {
                             "Prefer printk_ratelimited or pr_<level>_ratelimited to printk_ratelimit\n" . $herecurr);
                }
 
-# printk should use KERN_* levels.  Note that follow on printk's on the
-# same line do not need a level, so we use the current block context
-# to try and find and validate the current printk.  In summary the current
-# printk includes all preceding printk's which have no newline on the end.
-# we assume the first bad printk is the one to report.
-               if ($line =~ /\bprintk\((?!KERN_)\s*"/) {
-                       my $ok = 0;
-                       for (my $ln = $linenr - 1; $ln >= $first_line; $ln--) {
-                               #print "CHECK<$lines[$ln - 1]\n";
-                               # we have a preceding printk if it ends
-                               # with "\n" ignore it, else it is to blame
-                               if ($lines[$ln - 1] =~ m{\bprintk\(}) {
-                                       if ($rawlines[$ln - 1] !~ m{\\n"}) {
-                                               $ok = 1;
-                                       }
-                                       last;
-                               }
-                       }
-                       if ($ok == 0) {
-                               WARN("PRINTK_WITHOUT_KERN_LEVEL",
-                                    "printk() should include KERN_ facility level\n" . $herecurr);
-                       }
+# printk should use KERN_* levels
+               if ($line =~ /\bprintk\s*\(\s*(?!KERN_[A-Z]+\b)/) {
+                       WARN("PRINTK_WITHOUT_KERN_LEVEL",
+                            "printk() should include KERN_<LEVEL> facility level\n" . $herecurr);
                }
 
                if ($line =~ /\bprintk\s*\(\s*KERN_([A-Z]+)/) {
@@ -3890,10 +4098,12 @@ sub process {
 
 # function brace can't be on same line, except for #defines of do while,
 # or if closed on same line
-               if (($line=~/$Type\s*$Ident\(.*\).*\s*{/) and
-                   !($line=~/\#\s*define.*do\s\{/) and !($line=~/}/)) {
+               if ($perl_version_ok &&
+                   $sline =~ /$Type\s*$Ident\s*$balanced_parens\s*\{/ &&
+                   $sline !~ /\#\s*define\b.*do\s*\{/ &&
+                   $sline !~ /}/) {
                        if (ERROR("OPEN_BRACE",
-                                 "open brace '{' following function declarations go on the next line\n" . $herecurr) &&
+                                 "open brace '{' following function definitions go on the next line\n" . $herecurr) &&
                            $fix) {
                                fix_delete_line($fixlinenr, $rawline);
                                my $fixed_line = $rawline;
@@ -4014,7 +4224,7 @@ sub process {
                        my ($where, $prefix) = ($-[1], $1);
                        if ($prefix !~ /$Type\s+$/ &&
                            ($where != 0 || $prefix !~ /^.\s+$/) &&
-                           $prefix !~ /[{,]\s+$/) {
+                           $prefix !~ /[{,:]\s+$/) {
                                if (ERROR("BRACKET_SPACE",
                                          "space prohibited before open square bracket '['\n" . $herecurr) &&
                                    $fix) {
@@ -4339,11 +4549,11 @@ sub process {
 
                                        # messages are ERROR, but ?: are CHK
                                        if ($ok == 0) {
-                                               my $msg_type = \&ERROR;
-                                               $msg_type = \&CHK if (($op eq '?:' || $op eq '?' || $op eq ':') && $ctx =~ /VxV/);
+                                               my $msg_level = \&ERROR;
+                                               $msg_level = \&CHK if (($op eq '?:' || $op eq '?' || $op eq ':') && $ctx =~ /VxV/);
 
-                                               if (&{$msg_type}("SPACING",
-                                                                "spaces required around that '$op' $at\n" . $hereptr)) {
+                                               if (&{$msg_level}("SPACING",
+                                                                 "spaces required around that '$op' $at\n" . $hereptr)) {
                                                        $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " ";
                                                        if (defined $fix_elements[$n + 2]) {
                                                                $fix_elements[$n + 2] =~ s/^\s+//;
@@ -4404,11 +4614,11 @@ sub process {
 
 #need space before brace following if, while, etc
                if (($line =~ /\(.*\)\{/ && $line !~ /\($Type\)\{/) ||
-                   $line =~ /do\{/) {
+                   $line =~ /\b(?:else|do)\{/) {
                        if (ERROR("SPACING",
                                  "space required before the open brace '{'\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$fixlinenr] =~ s/^(\+.*(?:do|\)))\{/$1 {/;
+                               $fixed[$fixlinenr] =~ s/^(\+.*(?:do|else|\)))\{/$1 {/;
                        }
                }
 
@@ -4496,6 +4706,32 @@ sub process {
                        }
                }
 
+# check for unnecessary parentheses around comparisons in if uses
+# when !drivers/staging or command-line uses --strict
+               if (($realfile !~ m@^(?:drivers/staging/)@ || $check_orig) &&
+                   $perl_version_ok && defined($stat) &&
+                   $stat =~ /(^.\s*if\s*($balanced_parens))/) {
+                       my $if_stat = $1;
+                       my $test = substr($2, 1, -1);
+                       my $herectx;
+                       while ($test =~ /(?:^|[^\w\&\!\~])+\s*\(\s*([\&\!\~]?\s*$Lval\s*(?:$Compare\s*$FuncArg)?)\s*\)/g) {
+                               my $match = $1;
+                               # avoid parentheses around potential macro args
+                               next if ($match =~ /^\s*\w+\s*$/);
+                               if (!defined($herectx)) {
+                                       $herectx = $here . "\n";
+                                       my $cnt = statement_rawlines($if_stat);
+                                       for (my $n = 0; $n < $cnt; $n++) {
+                                               my $rl = raw_line($linenr, $n);
+                                               $herectx .=  $rl . "\n";
+                                               last if $rl =~ /^[ \+].*\{/;
+                                       }
+                               }
+                               CHK("UNNECESSARY_PARENTHESES",
+                                   "Unnecessary parentheses around '$match'\n" . $herectx);
+                       }
+               }
+
 #goto labels aren't indented, allow a single space however
                if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and
                   !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) {
@@ -4510,7 +4746,7 @@ sub process {
 # return is not a function
                if (defined($stat) && $stat =~ /^.\s*return(\s*)\(/s) {
                        my $spacing = $1;
-                       if ($^V && $^V ge 5.10.0 &&
+                       if ($perl_version_ok &&
                            $stat =~ /^.\s*return\s*($balanced_parens)\s*;\s*$/) {
                                my $value = $1;
                                $value = deparenthesize($value);
@@ -4537,7 +4773,7 @@ sub process {
                }
 
 # if statements using unnecessary parentheses - ie: if ((foo == bar))
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    $line =~ /\bif\s*((?:\(\s*){2,})/) {
                        my $openparens = $1;
                        my $count = $openparens =~ tr@\(@\(@;
@@ -4554,7 +4790,7 @@ sub process {
 #      avoid cases like "foo + BAR < baz"
 #      only fix matches surrounded by parentheses to avoid incorrect
 #      conversions like "FOO < baz() + 5" being "misfixed" to "baz() > FOO + 5"
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    $line =~ /^\+(.*)\b($Constant|[A-Z_][A-Z0-9_]*)\s*($Compare)\s*($LvalOrFunc)/) {
                        my $lead = $1;
                        my $const = $2;
@@ -4844,6 +5080,7 @@ sub process {
                        if (defined $define_args && $define_args ne "") {
                                $define_args = substr($define_args, 1, length($define_args) - 2);
                                $define_args =~ s/\s*//g;
+                               $define_args =~ s/\\\+?//g;
                                @def_args = split(",", $define_args);
                        }
 
@@ -4884,12 +5121,8 @@ sub process {
                        #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n";
 
                        $ctx =~ s/\n*$//;
-                       my $herectx = $here . "\n";
                        my $stmt_cnt = statement_rawlines($ctx);
-
-                       for (my $n = 0; $n < $stmt_cnt; $n++) {
-                               $herectx .= raw_line($linenr, $n) . "\n";
-                       }
+                       my $herectx = get_stat_here($linenr, $stmt_cnt, $here);
 
                        if ($dstat ne '' &&
                            $dstat !~ /^(?:$Ident|-?$Constant),$/ &&                    # 10, // foo(),
@@ -4944,7 +5177,7 @@ sub process {
                                $tmp_stmt =~ s/\b(typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g;
                                $tmp_stmt =~ s/\#+\s*$arg\b//g;
                                $tmp_stmt =~ s/\b$arg\s*\#\#//g;
-                               my $use_cnt = $tmp_stmt =~ s/\b$arg\b//g;
+                               my $use_cnt = () = $tmp_stmt =~ /\b$arg\b/g;
                                if ($use_cnt > 1) {
                                        CHK("MACRO_ARG_REUSE",
                                            "Macro argument reuse '$arg' - possible side-effects?\n" . "$herectx");
@@ -4961,12 +5194,9 @@ sub process {
 # check for macros with flow control, but without ## concatenation
 # ## concatenation is commonly a macro that defines a function so ignore those
                        if ($has_flow_statement && !$has_arg_concat) {
-                               my $herectx = $here . "\n";
                                my $cnt = statement_rawlines($ctx);
+                               my $herectx = get_stat_here($linenr, $cnt, $here);
 
-                               for (my $n = 0; $n < $cnt; $n++) {
-                                       $herectx .= raw_line($linenr, $n) . "\n";
-                               }
                                WARN("MACRO_WITH_FLOW_CONTROL",
                                     "Macros with flow control statements should be avoided\n" . "$herectx");
                        }
@@ -4986,7 +5216,7 @@ sub process {
 # do {} while (0) macro tests:
 # single-statement macros do not need to be enclosed in do while (0) loop,
 # macro should not end with a semicolon
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    $realfile !~ m@/vmlinux.lds.h$@ &&
                    $line =~ /^.\s*\#\s*define\s+$Ident(\()?/) {
                        my $ln = $linenr;
@@ -5006,11 +5236,7 @@ sub process {
 
                                $ctx =~ s/\n*$//;
                                my $cnt = statement_rawlines($ctx);
-                               my $herectx = $here . "\n";
-
-                               for (my $n = 0; $n < $cnt; $n++) {
-                                       $herectx .= raw_line($linenr, $n) . "\n";
-                               }
+                               my $herectx = get_stat_here($linenr, $cnt, $here);
 
                                if (($stmts =~ tr/;/;/) == 1 &&
                                    $stmts !~ /^\s*(if|while|for|switch)\b/) {
@@ -5024,27 +5250,13 @@ sub process {
                        } elsif ($dstat =~ /^\+\s*#\s*define\s+$Ident.*;\s*$/) {
                                $ctx =~ s/\n*$//;
                                my $cnt = statement_rawlines($ctx);
-                               my $herectx = $here . "\n";
-
-                               for (my $n = 0; $n < $cnt; $n++) {
-                                       $herectx .= raw_line($linenr, $n) . "\n";
-                               }
+                               my $herectx = get_stat_here($linenr, $cnt, $here);
 
                                WARN("TRAILING_SEMICOLON",
                                     "macros should not use a trailing semicolon\n" . "$herectx");
                        }
                }
 
-# make sure symbols are always wrapped with VMLINUX_SYMBOL() ...
-# all assignments may have only one of the following with an assignment:
-#      .
-#      ALIGN(...)
-#      VMLINUX_SYMBOL(...)
-               if ($realfile eq 'vmlinux.lds.h' && $line =~ /(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/) {
-                       WARN("MISSING_VMLINUX_SYMBOL",
-                            "vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\n" . $herecurr);
-               }
-
 # check for redundant bracing round if etc
                if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) {
                        my ($level, $endln, @chunks) =
@@ -5151,12 +5363,8 @@ sub process {
                                }
                        }
                        if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) {
-                               my $herectx = $here . "\n";
                                my $cnt = statement_rawlines($block);
-
-                               for (my $n = 0; $n < $cnt; $n++) {
-                                       $herectx .= raw_line($linenr, $n) . "\n";
-                               }
+                               my $herectx = get_stat_here($linenr, $cnt, $here);
 
                                WARN("BRACES",
                                     "braces {} are not necessary for single statement blocks\n" . $herectx);
@@ -5254,15 +5462,28 @@ sub process {
                }
 
 # concatenated string without spaces between elements
-               if ($line =~ /$String[A-Z_]/ || $line =~ /[A-Za-z0-9_]$String/) {
-                       CHK("CONCATENATED_STRING",
-                           "Concatenated strings should use spaces between elements\n" . $herecurr);
+               if ($line =~ /$String[A-Za-z0-9_]/ || $line =~ /[A-Za-z0-9_]$String/) {
+                       if (CHK("CONCATENATED_STRING",
+                               "Concatenated strings should use spaces between elements\n" . $herecurr) &&
+                           $fix) {
+                               while ($line =~ /($String)/g) {
+                                       my $extracted_string = substr($rawline, $-[0], $+[0] - $-[0]);
+                                       $fixed[$fixlinenr] =~ s/\Q$extracted_string\E([A-Za-z0-9_])/$extracted_string $1/;
+                                       $fixed[$fixlinenr] =~ s/([A-Za-z0-9_])\Q$extracted_string\E/$1 $extracted_string/;
+                               }
+                       }
                }
 
 # uncoalesced string fragments
                if ($line =~ /$String\s*"/) {
-                       WARN("STRING_FRAGMENTS",
-                            "Consecutive strings are generally better as a single string\n" . $herecurr);
+                       if (WARN("STRING_FRAGMENTS",
+                                "Consecutive strings are generally better as a single string\n" . $herecurr) &&
+                           $fix) {
+                               while ($line =~ /($String)(?=\s*")/g) {
+                                       my $extracted_string = substr($rawline, $-[0], $+[0] - $-[0]);
+                                       $fixed[$fixlinenr] =~ s/\Q$extracted_string\E\s*"/substr($extracted_string, 0, -1)/e;
+                               }
+                       }
                }
 
 # check for non-standard and hex prefixed decimal printf formats
@@ -5291,16 +5512,21 @@ sub process {
                }
 
 # check for line continuations in quoted strings with odd counts of "
-               if ($rawline =~ /\\$/ && $rawline =~ tr/"/"/ % 2) {
+               if ($rawline =~ /\\$/ && $sline =~ tr/"/"/ % 2) {
                        WARN("LINE_CONTINUATIONS",
                             "Avoid line continuations in quoted strings\n" . $herecurr);
                }
 
 # warn about #if 0
                if ($line =~ /^.\s*\#\s*if\s+0\b/) {
-                       CHK("REDUNDANT_CODE",
-                           "if this code is redundant consider removing it\n" .
-                               $herecurr);
+                       WARN("IF_0",
+                            "Consider removing the code enclosed by this #if 0 and its #endif\n" . $herecurr);
+               }
+
+# warn about #if 1
+               if ($line =~ /^.\s*\#\s*if\s+1\b/) {
+                       WARN("IF_1",
+                            "Consider removing the #if 1 and its #endif\n" . $herecurr);
                }
 
 # check for needless "if (<foo>) fn(<foo>)" uses
@@ -5371,7 +5597,7 @@ sub process {
                }
 
 # check for mask then right shift without a parentheses
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    $line =~ /$LvalOrFunc\s*\&\s*($LvalOrFunc)\s*>>/ &&
                    $4 !~ /^\&/) { # $LvalOrFunc may be &foo, ignore if so
                        WARN("MASK_THEN_SHIFT",
@@ -5379,7 +5605,7 @@ sub process {
                }
 
 # check for pointer comparisons to NULL
-               if ($^V && $^V ge 5.10.0) {
+               if ($perl_version_ok) {
                        while ($line =~ /\b$LvalOrFunc\s*(==|\!=)\s*NULL\b/g) {
                                my $val = $1;
                                my $equal = "!";
@@ -5570,6 +5796,12 @@ sub process {
                        }
                }
 
+# check for smp_read_barrier_depends and read_barrier_depends
+               if (!$file && $line =~ /\b(smp_|)read_barrier_depends\s*\(/) {
+                       WARN("READ_BARRIER_DEPENDS",
+                            "$1read_barrier_depends should only be used in READ_ONCE or DEC Alpha code\n" . $herecurr);
+               }
+
 # check of hardware specific defines
                if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) {
                        CHK("ARCH_DEFINES",
@@ -5616,13 +5848,6 @@ sub process {
                             "__packed is preferred over __attribute__((packed))\n" . $herecurr);
                }
 
-# Check for new packed members, warn to use care
-               if ($realfile !~ m@\binclude/uapi/@ &&
-                   $line =~ /\b(__attribute__\s*\(\s*\(.*\bpacked|__packed)\b/) {
-                       WARN("NEW_PACKED",
-                            "Adding new packed members is to be done with care\n" . $herecurr);
-               }
-
 # Check for __attribute__ aligned, prefer __aligned
                if ($realfile !~ m@\binclude/uapi/@ &&
                    $line =~ /\b__attribute__\s*\(\s*\(.*aligned/) {
@@ -5652,7 +5877,7 @@ sub process {
                }
 
 # Check for __attribute__ weak, or __weak declarations (may have link issues)
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    $line =~ /(?:$Declare|$DeclareMisordered)\s*$Ident\s*$balanced_parens\s*(?:$Attribute)?\s*;/ &&
                    ($line =~ /\b__attribute__\s*\(\s*\(.*\bweak\b/ ||
                     $line =~ /\b__weak\b/)) {
@@ -5733,34 +5958,55 @@ sub process {
                        }
                }
 
-               # check for vsprintf extension %p<foo> misuses
-               if ($^V && $^V ge 5.10.0 &&
+# check for vsprintf extension %p<foo> misuses
+               if ($perl_version_ok &&
                    defined $stat &&
                    $stat =~ /^\+(?![^\{]*\{\s*).*\b(\w+)\s*\(.*$String\s*,/s &&
                    $1 !~ /^_*volatile_*$/) {
-                       my $bad_extension = "";
+                       my $stat_real;
+
                        my $lc = $stat =~ tr@\n@@;
                        $lc = $lc + $linenr;
                        for (my $count = $linenr; $count <= $lc; $count++) {
+                               my $specifier;
+                               my $extension;
+                               my $bad_specifier = "";
                                my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0));
                                $fmt =~ s/%%//g;
-                               if ($fmt =~ /(\%[\*\d\.]*p(?![\WFfSsBKRraEhMmIiUDdgVCbGNO]).)/) {
-                                       $bad_extension = $1;
-                                       last;
+
+                               while ($fmt =~ /(\%[\*\d\.]*p(\w))/g) {
+                                       $specifier = $1;
+                                       $extension = $2;
+                                       if ($extension !~ /[SsBKRraEhMmIiUDdgVCbGNOx]/) {
+                                               $bad_specifier = $specifier;
+                                               last;
+                                       }
+                                       if ($extension eq "x" && !defined($stat_real)) {
+                                               if (!defined($stat_real)) {
+                                                       $stat_real = get_stat_real($linenr, $lc);
+                                               }
+                                               WARN("VSPRINTF_SPECIFIER_PX",
+                                                    "Using vsprintf specifier '\%px' potentially exposes the kernel memory layout, if you don't really need the address please consider using '\%p'.\n" . "$here\n$stat_real\n");
+                                       }
                                }
-                       }
-                       if ($bad_extension ne "") {
-                               my $stat_real = raw_line($linenr, 0);
-                               for (my $count = $linenr + 1; $count <= $lc; $count++) {
-                                       $stat_real = $stat_real . "\n" . raw_line($count, 0);
+                               if ($bad_specifier ne "") {
+                                       my $stat_real = get_stat_real($linenr, $lc);
+                                       my $ext_type = "Invalid";
+                                       my $use = "";
+                                       if ($bad_specifier =~ /p[Ff]/) {
+                                               $ext_type = "Deprecated";
+                                               $use = " - use %pS instead";
+                                               $use =~ s/pS/ps/ if ($bad_specifier =~ /pf/);
+                                       }
+
+                                       WARN("VSPRINTF_POINTER_EXTENSION",
+                                            "$ext_type vsprintf pointer extension '$bad_specifier'$use\n" . "$here\n$stat_real\n");
                                }
-                               WARN("VSPRINTF_POINTER_EXTENSION",
-                                    "Invalid vsprintf pointer extension '$bad_extension'\n" . "$here\n$stat_real\n");
                        }
                }
 
 # Check for misused memsets
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    defined $stat &&
                    $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*$FuncArg\s*\)/) {
 
@@ -5778,7 +6024,7 @@ sub process {
                }
 
 # Check for memcpy(foo, bar, ETH_ALEN) that could be ether_addr_copy(foo, bar)
-#              if ($^V && $^V ge 5.10.0 &&
+#              if ($perl_version_ok &&
 #                  defined $stat &&
 #                  $stat =~ /^\+(?:.*?)\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
 #                      if (WARN("PREFER_ETHER_ADDR_COPY",
@@ -5789,7 +6035,7 @@ sub process {
 #              }
 
 # Check for memcmp(foo, bar, ETH_ALEN) that could be ether_addr_equal*(foo, bar)
-#              if ($^V && $^V ge 5.10.0 &&
+#              if ($perl_version_ok &&
 #                  defined $stat &&
 #                  $stat =~ /^\+(?:.*?)\bmemcmp\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
 #                      WARN("PREFER_ETHER_ADDR_EQUAL",
@@ -5798,7 +6044,7 @@ sub process {
 
 # check for memset(foo, 0x0, ETH_ALEN) that could be eth_zero_addr
 # check for memset(foo, 0xFF, ETH_ALEN) that could be eth_broadcast_addr
-#              if ($^V && $^V ge 5.10.0 &&
+#              if ($perl_version_ok &&
 #                  defined $stat &&
 #                  $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
 #
@@ -5820,7 +6066,7 @@ sub process {
 #              }
 
 # typecasts on min/max could be min_t/max_t
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    defined $stat &&
                    $stat =~ /^\+(?:.*?)\b(min|max)\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) {
                        if (defined $2 || defined $7) {
@@ -5844,7 +6090,7 @@ sub process {
                }
 
 # check usleep_range arguments
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    defined $stat &&
                    $stat =~ /^\+(?:.*?)\busleep_range\s*\(\s*($FuncArg)\s*,\s*($FuncArg)\s*\)/) {
                        my $min = $1;
@@ -5860,7 +6106,7 @@ sub process {
                }
 
 # check for naked sscanf
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    defined $stat &&
                    $line =~ /\bsscanf\b/ &&
                    ($stat !~ /$Ident\s*=\s*sscanf\s*$balanced_parens/ &&
@@ -5868,24 +6114,18 @@ sub process {
                     $stat !~ /(?:$Compare)\s*\bsscanf\s*$balanced_parens/)) {
                        my $lc = $stat =~ tr@\n@@;
                        $lc = $lc + $linenr;
-                       my $stat_real = raw_line($linenr, 0);
-                       for (my $count = $linenr + 1; $count <= $lc; $count++) {
-                               $stat_real = $stat_real . "\n" . raw_line($count, 0);
-                       }
+                       my $stat_real = get_stat_real($linenr, $lc);
                        WARN("NAKED_SSCANF",
                             "unchecked sscanf return value\n" . "$here\n$stat_real\n");
                }
 
 # check for simple sscanf that should be kstrto<foo>
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    defined $stat &&
                    $line =~ /\bsscanf\b/) {
                        my $lc = $stat =~ tr@\n@@;
                        $lc = $lc + $linenr;
-                       my $stat_real = raw_line($linenr, 0);
-                       for (my $count = $linenr + 1; $count <= $lc; $count++) {
-                               $stat_real = $stat_real . "\n" . raw_line($count, 0);
-                       }
+                       my $stat_real = get_stat_real($linenr, $lc);
                        if ($stat_real =~ /\bsscanf\b\s*\(\s*$FuncArg\s*,\s*("[^"]+")/) {
                                my $format = $6;
                                my $count = $format =~ tr@%@%@;
@@ -5939,7 +6179,7 @@ sub process {
 
 # check for function declarations that have arguments without identifier names
                if (defined $stat &&
-                   $stat =~ /^.\s*(?:extern\s+)?$Type\s*$Ident\s*\(\s*([^{]+)\s*\)\s*;/s &&
+                   $stat =~ /^.\s*(?:extern\s+)?$Type\s*(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*\(\s*([^{]+)\s*\)\s*;/s &&
                    $1 ne "void") {
                        my $args = trim($1);
                        while ($args =~ m/\s*($Type\s*(?:$Ident|\(\s*\*\s*$Ident?\s*\)\s*$balanced_parens)?)/g) {
@@ -5952,7 +6192,7 @@ sub process {
                }
 
 # check for function definitions
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    defined $stat &&
                    $stat =~ /^.\s*(?:$Storage\s+)?$Type\s*($Ident)\s*$balanced_parens\s*{/s) {
                        $context_function = $1;
@@ -5992,14 +6232,14 @@ sub process {
 
 # alloc style
 # p = alloc(sizeof(struct foo), ...) should be p = alloc(sizeof(*p), ...)
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*([kv][mz]alloc(?:_node)?)\s*\(\s*(sizeof\s*\(\s*struct\s+$Lval\s*\))/) {
                        CHK("ALLOC_SIZEOF_STRUCT",
                            "Prefer $3(sizeof(*$1)...) over $3($4...)\n" . $herecurr);
                }
 
 # check for k[mz]alloc with multiplies that could be kmalloc_array/kcalloc
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    defined $stat &&
                    $stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) {
                        my $oldfunc = $3;
@@ -6015,12 +6255,9 @@ sub process {
                        }
                        if ($r1 !~ /^sizeof\b/ && $r2 =~ /^sizeof\s*\S/ &&
                            !($r1 =~ /^$Constant$/ || $r1 =~ /^[A-Z_][A-Z0-9_]*$/)) {
-                               my $ctx = '';
-                               my $herectx = $here . "\n";
                                my $cnt = statement_rawlines($stat);
-                               for (my $n = 0; $n < $cnt; $n++) {
-                                       $herectx .= raw_line($linenr, $n) . "\n";
-                               }
+                               my $herectx = get_stat_here($linenr, $cnt, $here);
+
                                if (WARN("ALLOC_WITH_MULTIPLY",
                                         "Prefer $newfunc over $oldfunc with multiply\n" . $herectx) &&
                                    $cnt == 1 &&
@@ -6031,8 +6268,9 @@ sub process {
                }
 
 # check for krealloc arg reuse
-               if ($^V && $^V ge 5.10.0 &&
-                   $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*\1\s*,/) {
+               if ($perl_version_ok &&
+                   $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*($Lval)\s*,/ &&
+                   $1 eq $3) {
                        WARN("KREALLOC_ARG_REUSE",
                             "Reusing the krealloc arg is almost always a bug\n" . $herecurr);
                }
@@ -6091,7 +6329,7 @@ sub process {
                                next if ($fline =~ /^.[\s$;]*$/);
                                $has_statement = 1;
                                $count++;
-                               $has_break = 1 if ($fline =~ /\bswitch\b|\b(?:break\s*;[\s$;]*$|return\b|goto\b|continue\b)/);
+                               $has_break = 1 if ($fline =~ /\bswitch\b|\b(?:break\s*;[\s$;]*$|exit\s*\(\b|return\b|goto\b|continue\b)/);
                        }
                        if (!$has_break && $has_statement) {
                                WARN("MISSING_BREAK",
@@ -6100,15 +6338,12 @@ sub process {
                }
 
 # check for switch/default statements without a break;
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    defined $stat &&
                    $stat =~ /^\+[$;\s]*(?:case[$;\s]+\w+[$;\s]*:[$;\s]*|)*[$;\s]*\bdefault[$;\s]*:[$;\s]*;/g) {
-                       my $ctx = '';
-                       my $herectx = $here . "\n";
                        my $cnt = statement_rawlines($stat);
-                       for (my $n = 0; $n < $cnt; $n++) {
-                               $herectx .= raw_line($linenr, $n) . "\n";
-                       }
+                       my $herectx = get_stat_here($linenr, $cnt, $here);
+
                        WARN("DEFAULT_NO_BREAK",
                             "switch default: should use break\n" . $herectx);
                }
@@ -6161,6 +6396,19 @@ sub process {
                        }
                }
 
+# check for bool bitfields
+               if ($sline =~ /^.\s+bool\s*$Ident\s*:\s*\d+\s*;/) {
+                       WARN("BOOL_BITFIELD",
+                            "Avoid using bool as bitfield.  Prefer bool bitfields as unsigned int or u<8|16|32>\n" . $herecurr);
+               }
+
+# check for bool use in .h files
+               if ($realfile =~ /\.h$/ &&
+                   $sline =~ /^.\s+bool\s*$Ident\s*(?::\s*d+\s*)?;/) {
+                       CHK("BOOL_MEMBER",
+                           "Avoid using bool structure members because of possible alignment issues - see: https://lkml.org/lkml/2017/11/21/384\n" . $herecurr);
+               }
+
 # check for semaphores initialized locked
                if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) {
                        WARN("CONSIDER_COMPLETION",
@@ -6207,7 +6455,7 @@ sub process {
                }
 
 # likely/unlikely comparisons similar to "(likely(foo) > 0)"
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    $line =~ /\b((?:un)?likely)\s*\(\s*$FuncArg\s*\)\s*$Compare/) {
                        WARN("LIKELY_MISUSE",
                             "Using $1 should generally have parentheses around the comparison\n" . $herecurr);
@@ -6224,28 +6472,6 @@ sub process {
                        }
                }
 
-# whine about ACCESS_ONCE
-               if ($^V && $^V ge 5.10.0 &&
-                   $line =~ /\bACCESS_ONCE\s*$balanced_parens\s*(=(?!=))?\s*($FuncArg)?/) {
-                       my $par = $1;
-                       my $eq = $2;
-                       my $fun = $3;
-                       $par =~ s/^\(\s*(.*)\s*\)$/$1/;
-                       if (defined($eq)) {
-                               if (WARN("PREFER_WRITE_ONCE",
-                                        "Prefer WRITE_ONCE(<FOO>, <BAR>) over ACCESS_ONCE(<FOO>) = <BAR>\n" . $herecurr) &&
-                                   $fix) {
-                                       $fixed[$fixlinenr] =~ s/\bACCESS_ONCE\s*\(\s*\Q$par\E\s*\)\s*$eq\s*\Q$fun\E/WRITE_ONCE($par, $fun)/;
-                               }
-                       } else {
-                               if (WARN("PREFER_READ_ONCE",
-                                        "Prefer READ_ONCE(<FOO>) over ACCESS_ONCE(<FOO>)\n" . $herecurr) &&
-                                   $fix) {
-                                       $fixed[$fixlinenr] =~ s/\bACCESS_ONCE\s*\(\s*\Q$par\E\s*\)/READ_ONCE($par)/;
-                               }
-                       }
-               }
-
 # check for mutex_trylock_recursive usage
                if ($line =~ /mutex_trylock_recursive/) {
                        ERROR("LOCKING",
@@ -6269,9 +6495,70 @@ sub process {
                             "Exporting world writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr);
                }
 
+# check for DEVICE_ATTR uses that could be DEVICE_ATTR_<FOO>
+# and whether or not function naming is typical and if
+# DEVICE_ATTR permissions uses are unusual too
+               if ($perl_version_ok &&
+                   defined $stat &&
+                   $stat =~ /\bDEVICE_ATTR\s*\(\s*(\w+)\s*,\s*\(?\s*(\s*(?:${multi_mode_perms_string_search}|0[0-7]{3,3})\s*)\s*\)?\s*,\s*(\w+)\s*,\s*(\w+)\s*\)/) {
+                       my $var = $1;
+                       my $perms = $2;
+                       my $show = $3;
+                       my $store = $4;
+                       my $octal_perms = perms_to_octal($perms);
+                       if ($show =~ /^${var}_show$/ &&
+                           $store =~ /^${var}_store$/ &&
+                           $octal_perms eq "0644") {
+                               if (WARN("DEVICE_ATTR_RW",
+                                        "Use DEVICE_ATTR_RW\n" . $herecurr) &&
+                                   $fix) {
+                                       $fixed[$fixlinenr] =~ s/\bDEVICE_ATTR\s*\(\s*$var\s*,\s*\Q$perms\E\s*,\s*$show\s*,\s*$store\s*\)/DEVICE_ATTR_RW(${var})/;
+                               }
+                       } elsif ($show =~ /^${var}_show$/ &&
+                                $store =~ /^NULL$/ &&
+                                $octal_perms eq "0444") {
+                               if (WARN("DEVICE_ATTR_RO",
+                                        "Use DEVICE_ATTR_RO\n" . $herecurr) &&
+                                   $fix) {
+                                       $fixed[$fixlinenr] =~ s/\bDEVICE_ATTR\s*\(\s*$var\s*,\s*\Q$perms\E\s*,\s*$show\s*,\s*NULL\s*\)/DEVICE_ATTR_RO(${var})/;
+                               }
+                       } elsif ($show =~ /^NULL$/ &&
+                                $store =~ /^${var}_store$/ &&
+                                $octal_perms eq "0200") {
+                               if (WARN("DEVICE_ATTR_WO",
+                                        "Use DEVICE_ATTR_WO\n" . $herecurr) &&
+                                   $fix) {
+                                       $fixed[$fixlinenr] =~ s/\bDEVICE_ATTR\s*\(\s*$var\s*,\s*\Q$perms\E\s*,\s*NULL\s*,\s*$store\s*\)/DEVICE_ATTR_WO(${var})/;
+                               }
+                       } elsif ($octal_perms eq "0644" ||
+                                $octal_perms eq "0444" ||
+                                $octal_perms eq "0200") {
+                               my $newshow = "$show";
+                               $newshow = "${var}_show" if ($show ne "NULL" && $show ne "${var}_show");
+                               my $newstore = $store;
+                               $newstore = "${var}_store" if ($store ne "NULL" && $store ne "${var}_store");
+                               my $rename = "";
+                               if ($show ne $newshow) {
+                                       $rename .= " '$show' to '$newshow'";
+                               }
+                               if ($store ne $newstore) {
+                                       $rename .= " '$store' to '$newstore'";
+                               }
+                               WARN("DEVICE_ATTR_FUNCTIONS",
+                                    "Consider renaming function(s)$rename\n" . $herecurr);
+                       } else {
+                               WARN("DEVICE_ATTR_PERMS",
+                                    "DEVICE_ATTR unusual permissions '$perms' used\n" . $herecurr);
+                       }
+               }
+
 # Mode permission misuses where it seems decimal should be octal
 # This uses a shortcut match to avoid unnecessary uses of a slow foreach loop
-               if ($^V && $^V ge 5.10.0 &&
+# o Ignore module_param*(...) uses with a decimal 0 permission as that has a
+#   specific definition of not visible in sysfs.
+# o Ignore proc_create*(...) uses with a decimal 0 permission as that means
+#   use the default permissions
+               if ($perl_version_ok &&
                    defined $stat &&
                    $line =~ /$mode_perms_search/) {
                        foreach my $entry (@mode_permission_funcs) {
@@ -6280,10 +6567,7 @@ sub process {
 
                                my $lc = $stat =~ tr@\n@@;
                                $lc = $lc + $linenr;
-                               my $stat_real = raw_line($linenr, 0);
-                               for (my $count = $linenr + 1; $count <= $lc; $count++) {
-                                       $stat_real = $stat_real . "\n" . raw_line($count, 0);
-                               }
+                               my $stat_real = get_stat_real($linenr, $lc);
 
                                my $skip_args = "";
                                if ($arg_pos > 1) {
@@ -6294,8 +6578,9 @@ sub process {
                                if ($stat =~ /$test/) {
                                        my $val = $1;
                                        $val = $6 if ($skip_args ne "");
-                                       if (($val =~ /^$Int$/ && $val !~ /^$Octal$/) ||
-                                           ($val =~ /^$Octal$/ && length($val) ne 4)) {
+                                       if (!($func =~ /^(?:module_param|proc_create)/ && $val eq "0") &&
+                                           (($val =~ /^$Int$/ && $val !~ /^$Octal$/) ||
+                                            ($val =~ /^$Octal$/ && length($val) ne 4))) {
                                                ERROR("NON_OCTAL_PERMISSIONS",
                                                      "Use 4 digit octal (0777) not decimal permissions\n" . "$here\n" . $stat_real);
                                        }
@@ -6308,30 +6593,13 @@ sub process {
                }
 
 # check for uses of S_<PERMS> that could be octal for readability
-               if ($line =~ /\b$mode_perms_string_search\b/) {
-                       my $val = "";
-                       my $oval = "";
-                       my $to = 0;
-                       my $curpos = 0;
-                       my $lastpos = 0;
-                       while ($line =~ /\b(($mode_perms_string_search)\b(?:\s*\|\s*)?\s*)/g) {
-                               $curpos = pos($line);
-                               my $match = $2;
-                               my $omatch = $1;
-                               last if ($lastpos > 0 && ($curpos - length($omatch) != $lastpos));
-                               $lastpos = $curpos;
-                               $to |= $mode_permission_string_types{$match};
-                               $val .= '\s*\|\s*' if ($val ne "");
-                               $val .= $match;
-                               $oval .= $omatch;
-                       }
-                       $oval =~ s/^\s*\|\s*//;
-                       $oval =~ s/\s*\|\s*$//;
-                       my $octal = sprintf("%04o", $to);
+               while ($line =~ m{\b($multi_mode_perms_string_search)\b}g) {
+                       my $oval = $1;
+                       my $octal = perms_to_octal($oval);
                        if (WARN("SYMBOLIC_PERMS",
                                 "Symbolic permissions '$oval' are not preferred. Consider using octal permissions '$octal'.\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$fixlinenr] =~ s/$val/$octal/;
+                               $fixed[$fixlinenr] =~ s/\Q$oval\E/$octal/;
                        }
                }
 
@@ -6372,13 +6640,18 @@ sub process {
                exit(0);
        }
 
-       if (!$is_patch && $file !~ /cover-letter\.patch$/) {
+       if (!$is_patch && $filename !~ /cover-letter\.patch$/) {
                ERROR("NOT_UNIFIED_DIFF",
                      "Does not appear to be a unified-diff format patch\n");
        }
-       if ($is_patch && $has_commit_log && $chk_signoff && $signoff == 0) {
-               ERROR("MISSING_SIGN_OFF",
-                     "Missing Signed-off-by: line(s)\n");
+       if ($is_patch && $has_commit_log && $chk_signoff) {
+               if ($signoff == 0) {
+                       ERROR("MISSING_SIGN_OFF",
+                             "Missing Signed-off-by: line(s)\n");
+               } elsif (!$authorsignoff) {
+                       WARN("NO_AUTHOR_SIGN_OFF",
+                            "Missing Signed-off-by: line by nominal patch author '$author'\n");
+               }
        }
 
        print report_dump();