ANDROID: mnt: Propagate remount correctly
[GitHub/exynos8895/android_kernel_samsung_universal8895.git] / scripts / checkpatch.pl
index 2b3c22808c3bfcd761ee6b7522354b77d31f3c9c..33e50614a5d9d8ce623a2e4ef9bfc7c00f5be476 100755 (executable)
@@ -27,12 +27,15 @@ my $emacs = 0;
 my $terse = 0;
 my $showfile = 0;
 my $file = 0;
+my $git = 0;
+my %git_commits = ();
 my $check = 0;
 my $check_orig = 0;
 my $summary = 1;
 my $mailback = 0;
 my $summary_file = 0;
 my $show_types = 0;
+my $list_types = 0;
 my $fix = 0;
 my $fix_inplace = 0;
 my $root;
@@ -51,7 +54,10 @@ my $min_conf_desc_length = 4;
 my $spelling_file = "$D/spelling.txt";
 my $codespell = 0;
 my $codespellfile = "/usr/share/codespell/dictionary.txt";
+my $conststructsfile = "$D/const_structs.checkpatch";
+my $typedefsfile = "";
 my $color = 1;
+my $allow_c99_comments = 1;
 
 sub help {
        my ($exitcode) = @_;
@@ -68,13 +74,24 @@ Options:
   --emacs                    emacs compile window format
   --terse                    one line per report
   --showfile                 emit diffed file position, not input file position
+  -g, --git                  treat FILE as a single commit or git revision range
+                             single git commit with:
+                               <rev>
+                               <rev>^
+                               <rev>~n
+                             multiple git commits with:
+                               <rev1>..<rev2>
+                               <rev1>...<rev2>
+                               <rev>-<count>
+                             git merges are ignored
   -f, --file                 treat FILE as regular source file
   --subjective, --strict     enable more subjective tests
+  --list-types               list the possible message types
   --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
   --min-conf-desc-length=n   set the min description length, if shorter, warn
-  --show-types               show the message "types" in the output
   --root=PATH                PATH to the kernel tree root
   --no-summary               suppress the per-file summary
   --mailback                 only produce a report in case of warnings/errors
@@ -97,6 +114,7 @@ Options:
   --codespell                Use the codespell dictionary for spelling/typos
                              (default:/usr/share/codespell/dictionary.txt)
   --codespellfile            Use this codespell dictionary
+  --typedefsfile             Read additional types from this file
   --color                    Use colors when output is STDOUT (default: on)
   -h, --help, --version      display this help and exit
 
@@ -106,6 +124,37 @@ EOM
        exit($exitcode);
 }
 
+sub uniq {
+       my %seen;
+       return grep { !$seen{$_}++ } @_;
+}
+
+sub list_types {
+       my ($exitcode) = @_;
+
+       my $count = 0;
+
+       local $/ = undef;
+
+       open(my $script, '<', abs_path($P)) or
+           die "$P: Can't read '$P' $!\n";
+
+       my $text = <$script>;
+       close($script);
+
+       my @types = ();
+       for ($text =~ /\b(?:(?:CHK|WARN|ERROR)\s*\(\s*"([^"]+)")/g) {
+               push (@types, $_);
+       }
+       @types = sort(uniq(@types));
+       print("#\tMessage type\n\n");
+       foreach my $type (@types) {
+               print(++$count . "\t" . $type . "\n");
+       }
+
+       exit($exitcode);
+}
+
 my $conf = which_conf($configuration_file);
 if (-f $conf) {
        my @conf_args;
@@ -141,11 +190,13 @@ GetOptions(
        'terse!'        => \$terse,
        'showfile!'     => \$showfile,
        'f|file!'       => \$file,
+       'g|git!'        => \$git,
        'subjective!'   => \$check,
        'strict!'       => \$check,
        'ignore=s'      => \@ignore,
        'types=s'       => \@use,
        'show-types!'   => \$show_types,
+       'list-types!'   => \$list_types,
        'max-line-length=i' => \$max_line_length,
        'min-conf-desc-length=i' => \$min_conf_desc_length,
        'root=s'        => \$root,
@@ -159,6 +210,7 @@ GetOptions(
        'test-only=s'   => \$tst_only,
        'codespell!'    => \$codespell,
        'codespellfile=s'       => \$codespellfile,
+       'typedefsfile=s'        => \$typedefsfile,
        'color!'        => \$color,
        'h|help'        => \$help,
        'version'       => \$help
@@ -166,6 +218,8 @@ GetOptions(
 
 help(0) if ($help);
 
+list_types(0) if ($list_types);
+
 $fix = 1 if ($fix_inplace);
 $check_orig = $check;
 
@@ -178,9 +232,9 @@ if ($^V && $^V lt $minimum_perl_version) {
        }
 }
 
+#if no filenames are given, push '-' to read patch from stdin
 if ($#ARGV < 0) {
-       print "$P: no input files\n";
-       exit(1);
+       push(@ARGV, '-');
 }
 
 sub hash_save_array_words {
@@ -264,12 +318,12 @@ our $Sparse       = qr{
                        __kernel|
                        __force|
                        __iomem|
-                       __pmem|
                        __must_check|
                        __init_refok|
                        __kprobes|
                        __ref|
-                       __rcu
+                       __rcu|
+                       __private
                }x;
 our $InitAttributePrefix = qr{__(?:mem|cpu|dev|net_|)};
 our $InitAttributeData = qr{$InitAttributePrefix(?:initdata\b)};
@@ -284,7 +338,7 @@ our $Attribute      = qr{
                        __percpu|
                        __nocast|
                        __safe|
-                       __bitwise__|
+                       __bitwise|
                        __packed__|
                        __packed2__|
                        __naked|
@@ -373,7 +427,7 @@ our $typeTypedefs = qr{(?x:
 our $zero_initializer = qr{(?:(?:0[xX])?0+$Int_type?|NULL|false)\b};
 
 our $logFunctions = qr{(?x:
-       printk(?:_ratelimited|_once|)|
+       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|)|
        WARN(?:_RATELIMIT|_ONCE|)|
        panic|
@@ -433,6 +487,28 @@ our @typeList = (
        qr{${Ident}_handler_fn},
        @typeListMisordered,
 );
+
+our $C90_int_types = qr{(?x:
+       long\s+long\s+int\s+(?:un)?signed|
+       long\s+long\s+(?:un)?signed\s+int|
+       long\s+long\s+(?:un)?signed|
+       (?:(?:un)?signed\s+)?long\s+long\s+int|
+       (?:(?:un)?signed\s+)?long\s+long|
+       int\s+long\s+long\s+(?:un)?signed|
+       int\s+(?:(?:un)?signed\s+)?long\s+long|
+
+       long\s+int\s+(?:un)?signed|
+       long\s+(?:un)?signed\s+int|
+       long\s+(?:un)?signed|
+       (?:(?:un)?signed\s+)?long\s+int|
+       (?:(?:un)?signed\s+)?long|
+       int\s+long\s+(?:un)?signed|
+       int\s+(?:(?:un)?signed\s+)?long|
+
+       int\s+(?:un)?signed|
+       (?:(?:un)?signed\s+)?int
+)};
+
 our @typeListFile = ();
 our @typeListWithAttr = (
        @typeList,
@@ -451,7 +527,11 @@ our @mode_permission_funcs = (
        ["module_param_array_named", 5],
        ["debugfs_create_(?:file|u8|u16|u32|u64|x8|x16|x32|x64|size_t|atomic_t|bool|blob|regset32|u32_array)", 2],
        ["proc_create(?:_data|)", 2],
-       ["(?:CLASS|DEVICE|SENSOR)_ATTR", 2],
+       ["(?:CLASS|DEVICE|SENSOR|SENSOR_DEVICE|IIO_DEVICE)_ATTR", 2],
+       ["IIO_DEV_ATTR_[A-Z_]+", 1],
+       ["SENSOR_(?:DEVICE_|)ATTR_2", 2],
+       ["SENSOR_TEMPLATE(?:_2|)", 3],
+       ["__ATTR", 2],
 );
 
 #Create a search pattern for all these functions to speed up a loop below
@@ -469,6 +549,32 @@ our $mode_perms_world_writable = qr{
        0[0-7][0-7][2367]
 }x;
 
+our %mode_permission_string_types = (
+       "S_IRWXU" => 0700,
+       "S_IRUSR" => 0400,
+       "S_IWUSR" => 0200,
+       "S_IXUSR" => 0100,
+       "S_IRWXG" => 0070,
+       "S_IRGRP" => 0040,
+       "S_IWGRP" => 0020,
+       "S_IXGRP" => 0010,
+       "S_IRWXO" => 0007,
+       "S_IROTH" => 0004,
+       "S_IWOTH" => 0002,
+       "S_IXOTH" => 0001,
+       "S_IRWXUGO" => 0777,
+       "S_IRUGO" => 0444,
+       "S_IWUGO" => 0222,
+       "S_IXUGO" => 0111,
+);
+
+#Create a search pattern for all these strings to speed up a loop below
+our $mode_perms_string_search = "";
+foreach my $entry (keys %mode_permission_string_types) {
+       $mode_perms_string_search .= '|' if ($mode_perms_string_search ne "");
+       $mode_perms_string_search .= $entry;
+}
+
 our $allowed_asm_includes = qr{(?x:
        irq|
        memory|
@@ -526,6 +632,44 @@ if ($codespell) {
 
 $misspellings = join("|", sort keys %spelling_fix) if keys %spelling_fix;
 
+sub read_words {
+       my ($wordsRef, $file) = @_;
+
+       if (open(my $words, '<', $file)) {
+               while (<$words>) {
+                       my $line = $_;
+
+                       $line =~ s/\s*\n?$//g;
+                       $line =~ s/^\s*//g;
+
+                       next if ($line =~ m/^\s*#/);
+                       next if ($line =~ m/^\s*$/);
+                       if ($line =~ /\s/) {
+                               print("$file: '$line' invalid - ignored\n");
+                               next;
+                       }
+
+                       $$wordsRef .= '|' if ($$wordsRef ne "");
+                       $$wordsRef .= $line;
+               }
+               close($file);
+               return 1;
+       }
+
+       return 0;
+}
+
+my $const_structs = "";
+read_words(\$const_structs, $conststructsfile)
+    or warn "No structs that should be const will be found - file '$conststructsfile': $!\n";
+
+my $typeOtherTypedefs = "";
+if (length($typedefsfile)) {
+       read_words(\$typeOtherTypedefs, $typedefsfile)
+           or warn "No additional types will be considered - file '$typedefsfile': $!\n";
+}
+$typeTypedefs .= '|' . $typeOtherTypedefs if ($typeOtherTypedefs ne "");
+
 sub build_types {
        my $mods = "(?x:  \n" . join("|\n  ", (@modifierList, @modifierListFile)) . "\n)";
        my $all = "(?x:  \n" . join("|\n  ", (@typeList, @typeListFile)) . "\n)";
@@ -632,6 +776,16 @@ sub seed_camelcase_file {
        }
 }
 
+sub is_maintained_obsolete {
+       my ($filename) = @_;
+
+       return 0 if (!$tree || !(-e "$root/scripts/get_maintainer.pl"));
+
+       my $status = `perl $root/scripts/get_maintainer.pl --status --nom --nol --nogit --nogit-fallback -f $filename 2>&1`;
+
+       return $status =~ /obsolete/i;
+}
+
 my $camelcase_seeded = 0;
 sub seed_camelcase_includes {
        return if ($camelcase_seeded);
@@ -729,10 +883,42 @@ my @fixed_inserted = ();
 my @fixed_deleted = ();
 my $fixlinenr = -1;
 
+# If input is git commits, extract all commits from the commit expressions.
+# For example, HEAD-3 means we need check 'HEAD, HEAD~1, HEAD~2'.
+die "$P: No git repository found\n" if ($git && !-e ".git");
+
+if ($git) {
+       my @commits = ();
+       foreach my $commit_expr (@ARGV) {
+               my $git_range;
+               if ($commit_expr =~ m/^(.*)-(\d+)$/) {
+                       $git_range = "-$2 $1";
+               } elsif ($commit_expr =~ m/\.\./) {
+                       $git_range = "$commit_expr";
+               } else {
+                       $git_range = "-1 $commit_expr";
+               }
+               my $lines = `git log --no-color --no-merges --pretty=format:'%H %s' $git_range`;
+               foreach my $line (split(/\n/, $lines)) {
+                       $line =~ /^([0-9a-fA-F]{40,40}) (.*)$/;
+                       next if (!defined($1) || !defined($2));
+                       my $sha1 = $1;
+                       my $subject = $2;
+                       unshift(@commits, $sha1);
+                       $git_commits{$sha1} = $subject;
+               }
+       }
+       die "$P: no git commits after extraction!\n" if (@commits == 0);
+       @ARGV = @commits;
+}
+
 my $vname;
 for my $filename (@ARGV) {
        my $FILE;
-       if ($file) {
+       if ($git) {
+               open($FILE, '-|', "git format-patch -M --stdout -1 $filename") ||
+                       die "$P: $filename: git format-patch failed - $!\n";
+       } elsif ($file) {
                open($FILE, '-|', "diff -u /dev/null $filename") ||
                        die "$P: $filename: diff failed - $!\n";
        } elsif ($filename eq '-') {
@@ -743,6 +929,8 @@ for my $filename (@ARGV) {
        }
        if ($filename eq '-') {
                $vname = 'Your patch';
+       } elsif ($git) {
+               $vname = "Commit " . substr($filename, 0, 12) . ' ("' . $git_commits{$filename} . '")';
        } else {
                $vname = $filename;
        }
@@ -1039,6 +1227,11 @@ sub sanitise_line {
                $res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@;
        }
 
+       if ($allow_c99_comments && $res =~ m@(//.*$)@) {
+               my $match = $1;
+               $res =~ s/\Q$match\E/"$;" x length($match)/e;
+       }
+
        return $res;
 }
 
@@ -1673,6 +1866,8 @@ my $prefix = '';
 sub show_type {
        my ($type) = @_;
 
+       $type =~ tr/[a-z]/[A-Z]/;
+
        return defined $use_type{$type} if (scalar keys %use_type > 0);
 
        return !defined $ignore_type{$type};
@@ -1958,7 +2153,8 @@ sub process {
        my $is_patch = 0;
        my $in_header_lines = $file ? 0 : 1;
        my $in_commit_log = 0;          #Scanning lines before patch
-       my $commit_log_possible_stack_dump = 0;
+       my $has_commit_log = 0;         #Encountered lines before patch
+       my $commit_log_possible_stack_dump = 0;
        my $commit_log_long_line = 0;
        my $commit_log_has_diff = 0;
        my $reported_maintainer_file = 0;
@@ -1978,6 +2174,7 @@ sub process {
        my $realline = 0;
        my $realcnt = 0;
        my $here = '';
+       my $context_function;           #undef'd unless there's a known function
        my $in_comment = 0;
        my $comment_edge = 0;
        my $first_line = 0;
@@ -2011,12 +2208,12 @@ sub process {
 
                if ($rawline=~/^\+\+\+\s+(\S+)/) {
                        $setup_docs = 0;
-                       if ($1 =~ m@Documentation/kernel-parameters.txt$@) {
+                       if ($1 =~ m@Documentation/admin-guide/kernel-parameters.rst$@) {
                                $setup_docs = 1;
                        }
                        #next;
                }
-               if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
+               if ($rawline =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
                        $realline=$1-1;
                        if (defined $2) {
                                $realcnt=$3+1;
@@ -2095,7 +2292,8 @@ sub process {
 
 #extract the line range in the file after the patch is applied
                if (!$in_commit_log &&
-                   $line =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
+                   $line =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@(.*)/) {
+                       my $context = $4;
                        $is_patch = 1;
                        $first_line = $linenr + 1;
                        $realline=$1-1;
@@ -2111,6 +2309,11 @@ sub process {
                        %suppress_whiletrailers = ();
                        %suppress_export = ();
                        $suppress_statement = 0;
+                       if ($context =~ /\b(\w+)\s*\(/) {
+                               $context_function = $1;
+                       } else {
+                               undef $context_function;
+                       }
                        next;
 
 # track the line number as we move through the hunk, note that
@@ -2177,6 +2380,10 @@ sub process {
                }
 
                if ($found_file) {
+                       if (is_maintained_obsolete($realfile)) {
+                               WARN("OBSOLETE",
+                                    "$realfile is marked as 'obsolete' in the MAINTAINERS hierarchy.  No unnecessary modifications please.\n");
+                       }
                        if ($realfile =~ m@^(?:drivers/net/|net/|drivers/staging/)@) {
                                $check = 1;
                        } else {
@@ -2348,8 +2555,10 @@ sub process {
 
 # Check for git id commit length and improperly formed commit descriptions
                if ($in_commit_log && !$commit_log_possible_stack_dump &&
+                   $line !~ /^\s*(?:Link|Patchwork|http|https|BugLink):/i &&
+                   $line !~ /^This reverts commit [0-9a-f]{7,40}/ &&
                    ($line =~ /\bcommit\s+[0-9a-f]{5,}\b/i ||
-                    ($line =~ /\b[0-9a-f]{12,40}\b/i &&
+                    ($line =~ /(?:\s|^)[0-9a-f]{12,40}(?:[\s"'\(\[]|$)/i &&
                      $line !~ /[\<\[][0-9a-f]{12,40}[\>\]]/i &&
                      $line !~ /\bfixes:\s*[0-9a-f]{12,40}/i))) {
                        my $init_char = "c";
@@ -2408,6 +2617,7 @@ sub process {
                     $line =~ /^rename (?:from|to) [\w\/\.\-]+\s*$/ ||
                     ($line =~ /\{\s*([\w\/\.\-]*)\s*\=\>\s*([\w\/\.\-]*)\s*\}/ &&
                      (defined($1) || defined($2))))) {
+                       $is_patch = 1;
                        $reported_maintainer_file = 1;
                        WARN("FILE_PATH_CHANGES",
                             "added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr);
@@ -2420,20 +2630,6 @@ sub process {
                                $herecurr) if (!$emitted_corrupt++);
                }
 
-# Check for absolute kernel paths.
-               if ($tree) {
-                       while ($line =~ m{(?:^|\s)(/\S*)}g) {
-                               my $file = $1;
-
-                               if ($file =~ m{^(.*?)(?::\d+)+:?$} &&
-                                   check_absolute_file($1, $herecurr)) {
-                                       #
-                               } else {
-                                       check_absolute_file($file, $herecurr);
-                               }
-                       }
-               }
-
 # UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php
                if (($realfile =~ /^$/ || $line =~ /^\+/) &&
                    $rawline !~ m/^$UTF8*$/) {
@@ -2450,10 +2646,11 @@ sub process {
 # Check if it's the start of a commit log
 # (not a header line and we haven't seen the patch filename)
                if ($in_header_lines && $realfile =~ /^$/ &&
-                   !($rawline =~ /^\s+\S/ ||
-                     $rawline =~ /^(commit\b|from\b|[\w-]+:).*$/i)) {
+                   !($rawline =~ /^\s+(?:\S|$)/ ||
+                     $rawline =~ /^(?:commit\b|from\b|[\w-]+:)/i)) {
                        $in_header_lines = 0;
                        $in_commit_log = 1;
+                       $has_commit_log = 1;
                }
 
 # Check if there is UTF-8 in a commit log when a mail header has explicitly
@@ -2470,6 +2667,20 @@ sub process {
                            "8-bit UTF-8 used in possible commit log\n" . $herecurr);
                }
 
+# Check for absolute kernel paths in commit message
+               if ($tree && $in_commit_log) {
+                       while ($line =~ m{(?:^|\s)(/\S*)}g) {
+                               my $file = $1;
+
+                               if ($file =~ m{^(.*?)(?::\d+)+:?$} &&
+                                   check_absolute_file($1, $herecurr)) {
+                                       #
+                               } else {
+                                       check_absolute_file($file, $herecurr);
+                               }
+                       }
+               }
+
 # Check for various typo / spelling mistakes
                if (defined($misspellings) &&
                    ($in_commit_log || $line =~ /^(?:\+|Subject:)/i)) {
@@ -2512,6 +2723,7 @@ sub process {
 
 # Check for FSF mailing addresses.
                if ($rawline =~ /\bwrite to the Free/i ||
+                   $rawline =~ /\b675\s+Mass\s+Ave/i ||
                    $rawline =~ /\b59\s+Temple\s+Pl/i ||
                    $rawline =~ /\b51\s+Franklin\s+St/i) {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
@@ -2563,13 +2775,6 @@ sub process {
                        #print "is_start<$is_start> is_end<$is_end> length<$length>\n";
                }
 
-# discourage the addition of CONFIG_EXPERIMENTAL in Kconfig.
-               if ($realfile =~ /Kconfig/ &&
-                   $line =~ /.\s*depends on\s+.*\bEXPERIMENTAL\b/) {
-                       WARN("CONFIG_EXPERIMENTAL",
-                            "Use of CONFIG_EXPERIMENTAL is deprecated. For alternatives, see https://lkml.org/lkml/2012/10/23/580\n");
-               }
-
 # discourage the use of boolean for type definition attributes of Kconfig options
                if ($realfile =~ /Kconfig/ &&
                    $line =~ /^\+\s*\bboolean\b/) {
@@ -2623,7 +2828,7 @@ sub process {
                }
 
 # check we are in a valid source file if not then ignore this hunk
-               next if ($realfile !~ /\.(h|c|s|S|pl|sh|dtsi|dts)$/);
+               next if ($realfile !~ /\.(h|c|s|S|sh|dtsi|dts)$/);
 
 # line length limit (with some exclusions)
 #
@@ -2657,6 +2862,10 @@ sub process {
                                 $line =~ /^\+\s*#\s*define\s+\w+\s+$String$/) {
                                $msg_type = "";
 
+                       # EFI_GUID is another special case
+                       } elsif ($line =~ /^\+.*\bEFI_GUID\s*\(/) {
+                               $msg_type = "";
+
                        # Otherwise set the alternate message types
 
                        # a comment starts before $max_line_length
@@ -2732,6 +2941,19 @@ sub process {
                            "Logical continuations should be on the previous line\n" . $hereprev);
                }
 
+# 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*$))/) {
+                       my $indent = length($1);
+                       if ($indent % 8) {
+                               if (WARN("TABSTOP",
+                                        "Statements should start on a tabstop\n" . $herecurr) &&
+                                   $fix) {
+                                       $fixed[$fixlinenr] =~ s@(^\+\t+) +@$1 . "\t" x ($indent/8)@e;
+                               }
+                       }
+               }
+
 # check multi-line statement indentation matches previous line
                if ($^V && $^V ge 5.10.0 &&
                    $prevline =~ /^\+([ \t]*)((?:$c90_Keywords(?:\s+if)\s*)|(?:$Declare\s*)?(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*|$Ident\s*=\s*$Ident\s*)\(.*(\&\&|\|\||,)\s*$/) {
@@ -2808,6 +3030,30 @@ sub process {
                             "Block comments use a trailing */ on a separate line\n" . $herecurr);
                }
 
+# Block comment * alignment
+               if ($prevline =~ /$;[ \t]*$/ &&                 #ends in comment
+                   $line =~ /^\+[ \t]*$;/ &&                   #leading comment
+                   $rawline =~ /^\+[ \t]*\*/ &&                #leading *
+                   (($prevrawline =~ /^\+.*?\/\*/ &&           #leading /*
+                     $prevrawline !~ /\*\/[ \t]*$/) ||         #no trailing */
+                    $prevrawline =~ /^\+[ \t]*\*/)) {          #leading *
+                       my $oldindent;
+                       $prevrawline =~ m@^\+([ \t]*/?)\*@;
+                       if (defined($1)) {
+                               $oldindent = expand_tabs($1);
+                       } else {
+                               $prevrawline =~ m@^\+(.*/?)\*@;
+                               $oldindent = expand_tabs($1);
+                       }
+                       $rawline =~ m@^\+([ \t]*)\*@;
+                       my $newindent = $1;
+                       $newindent = expand_tabs($newindent);
+                       if (length($oldindent) ne length($newindent)) {
+                               WARN("BLOCK_COMMENT_STYLE",
+                                    "Block comments should align the * on each line\n" . $hereprev);
+                       }
+               }
+
 # check for missing blank lines after struct/union declarations
 # with exceptions for various attributes and macros
                if ($prevline =~ /^[\+ ]};?\s*$/ &&
@@ -2898,6 +3144,17 @@ sub process {
 # check we are in a valid C source file if not then ignore this hunk
                next if ($realfile !~ /\.(h|c)$/);
 
+# check if this appears to be the start function declaration, save the name
+               if ($sline =~ /^\+\{\s*$/ &&
+                   $prevline =~ /^\+(?:(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*)?($Ident)\(/) {
+                       $context_function = $1;
+               }
+
+# check if this appears to be the end of function declaration
+               if ($sline =~ /^\+\}\s*$/) {
+                       undef $context_function;
+               }
+
 # check indentation of any line with a bare else
 # (but not if it is a multiple line "if (foo) return bar; else return baz;")
 # if the previous line is a break or return and is indented 1 tab more...
@@ -2922,12 +3179,6 @@ sub process {
                        }
                }
 
-# discourage the addition of CONFIG_EXPERIMENTAL in #if(def).
-               if ($line =~ /^\+\s*\#\s*if.*\bCONFIG_EXPERIMENTAL\b/) {
-                       WARN("CONFIG_EXPERIMENTAL",
-                            "Use of CONFIG_EXPERIMENTAL is deprecated. For alternatives, see https://lkml.org/lkml/2012/10/23/580\n");
-               }
-
 # check for RCS/CVS revision markers
                if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) {
                        WARN("CVS_KEYWORD",
@@ -3103,7 +3354,7 @@ sub process {
                }
 
 # Check relative indent for conditionals and blocks.
-               if ($line =~ /\b(?:(?:if|while|for|(?:[a-z_]+|)for_each[a-z_]+)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
+               if ($line =~ /\b(?:(?:if|while|for|(?:[a-z_]+|)for_each[a-z_]+)\s*\(|(?:do|else)\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
                        ($stat, $cond, $line_nr_next, $remain_next, $off_next) =
                                ctx_statement_block($linenr, $realcnt, 0)
                                        if (!defined $stat);
@@ -3195,6 +3446,8 @@ sub process {
                        if ($check && $s ne '' &&
                            (($sindent % 8) != 0 ||
                             ($sindent < $indent) ||
+                            ($sindent == $indent &&
+                             ($s !~ /^\s*(?:\}|\{|else\b)/)) ||
                             ($sindent > $indent + 8))) {
                                WARN("SUSPECT_CODE_INDENT",
                                     "suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n");
@@ -3217,6 +3470,42 @@ sub process {
 #ignore lines not being added
                next if ($line =~ /^[^\+]/);
 
+# check for dereferences that span multiple lines
+               if ($prevline =~ /^\+.*$Lval\s*(?:\.|->)\s*$/ &&
+                   $line =~ /^\+\s*(?!\#\s*(?!define\s+|if))\s*$Lval/) {
+                       $prevline =~ /($Lval\s*(?:\.|->))\s*$/;
+                       my $ref = $1;
+                       $line =~ /^.\s*($Lval)/;
+                       $ref .= $1;
+                       $ref =~ s/\s//g;
+                       WARN("MULTILINE_DEREFERENCE",
+                            "Avoid multiple line dereference - prefer '$ref'\n" . $hereprev);
+               }
+
+# check for declarations of signed or unsigned without int
+               while ($line =~ m{\b($Declare)\s*(?!char\b|short\b|int\b|long\b)\s*($Ident)?\s*[=,;\[\)\(]}g) {
+                       my $type = $1;
+                       my $var = $2;
+                       $var = "" if (!defined $var);
+                       if ($type =~ /^(?:(?:$Storage|$Inline|$Attribute)\s+)*((?:un)?signed)((?:\s*\*)*)\s*$/) {
+                               my $sign = $1;
+                               my $pointer = $2;
+
+                               $pointer = "" if (!defined $pointer);
+
+                               if (WARN("UNSPECIFIED_INT",
+                                        "Prefer '" . trim($sign) . " int" . rtrim($pointer) . "' to bare use of '$sign" . rtrim($pointer) . "'\n" . $herecurr) &&
+                                   $fix) {
+                                       my $decl = trim($sign) . " int ";
+                                       my $comp_pointer = $pointer;
+                                       $comp_pointer =~ s/\s//g;
+                                       $decl .= $comp_pointer;
+                                       $decl = rtrim($decl) if ($var eq "");
+                                       $fixed[$fixlinenr] =~ s@\b$sign\s*\Q$pointer\E\s*$var\b@$decl$var@;
+                               }
+                       }
+               }
+
 # TEST: allow direct testing of the type matcher.
                if ($dbg_type) {
                        if ($line =~ /^.\s*$Declare\s*$/) {
@@ -3252,7 +3541,7 @@ sub process {
                                $fixedline =~ s/\s*=\s*$/ = {/;
                                fix_insert_line($fixlinenr, $fixedline);
                                $fixedline = $line;
-                               $fixedline =~ s/^(.\s*){\s*/$1/;
+                               $fixedline =~ s/^(.\s*)\{\s*/$1/;
                                fix_insert_line($fixlinenr, $fixedline);
                        }
                }
@@ -3415,22 +3704,13 @@ sub process {
                        }
                }
 
-# check for uses of DEFINE_PCI_DEVICE_TABLE
-               if ($line =~ /\bDEFINE_PCI_DEVICE_TABLE\s*\(\s*(\w+)\s*\)\s*=/) {
-                       if (WARN("DEFINE_PCI_DEVICE_TABLE",
-                                "Prefer struct pci_device_id over deprecated DEFINE_PCI_DEVICE_TABLE\n" . $herecurr) &&
-                           $fix) {
-                               $fixed[$fixlinenr] =~ s/\b(?:static\s+|)DEFINE_PCI_DEVICE_TABLE\s*\(\s*(\w+)\s*\)\s*=\s*/static const struct pci_device_id $1\[\] = /;
-                       }
-               }
-
 # check for new typedefs, only function parameters and sparse annotations
 # make sense.
                if ($line =~ /\btypedef\s/ &&
                    $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ &&
                    $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ &&
                    $line !~ /\b$typeTypedefs\b/ &&
-                   $line !~ /\b__bitwise(?:__|)\b/) {
+                   $line !~ /\b__bitwise\b/) {
                        WARN("NEW_TYPEDEFS",
                             "do not add new typedefs\n" . $herecurr);
                }
@@ -3602,7 +3882,7 @@ sub process {
                                my $fixedline = rtrim($prevrawline) . " {";
                                fix_insert_line($fixlinenr, $fixedline);
                                $fixedline = $rawline;
-                               $fixedline =~ s/^(.\s*){\s*/$1\t/;
+                               $fixedline =~ s/^(.\s*)\{\s*/$1\t/;
                                if ($fixedline !~ /^\+\s*$/) {
                                        fix_insert_line($fixlinenr, $fixedline);
                                }
@@ -4086,12 +4366,12 @@ sub process {
 ##             }
 
 #need space before brace following if, while, etc
-               if (($line =~ /\(.*\)\{/ && $line !~ /\($Type\){/) ||
+               if (($line =~ /\(.*\)\{/ && $line !~ /\($Type\)\{/) ||
                    $line =~ /do\{/) {
                        if (ERROR("SPACING",
                                  "space required before the open brace '{'\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$fixlinenr] =~ s/^(\+.*(?:do|\))){/$1 {/;
+                               $fixed[$fixlinenr] =~ s/^(\+.*(?:do|\)))\{/$1 {/;
                        }
                }
 
@@ -4244,7 +4524,7 @@ sub process {
                        my $comp = $3;
                        my $to = $4;
                        my $newcomp = $comp;
-                       if ($lead !~ /$Operators\s*$/ &&
+                       if ($lead !~ /(?:$Operators|\.)\s*$/ &&
                            $to !~ /^(?:Constant|[A-Z_][A-Z0-9_]*)$/ &&
                            WARN("CONSTANT_COMPARISON",
                                 "Comparisons should place the constant on the right side of the test\n" . $herecurr) &&
@@ -4517,9 +4797,19 @@ sub process {
                        #print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n";
 
                        $has_flow_statement = 1 if ($ctx =~ /\b(goto|return)\b/);
-                       $has_arg_concat = 1 if ($ctx =~ /\#\#/);
+                       $has_arg_concat = 1 if ($ctx =~ /\#\#/ && $ctx !~ /\#\#\s*(?:__VA_ARGS__|args)\b/);
+
+                       $dstat =~ s/^.\s*\#\s*define\s+$Ident(\([^\)]*\))?\s*//;
+                       my $define_args = $1;
+                       my $define_stmt = $dstat;
+                       my @def_args = ();
+
+                       if (defined $define_args && $define_args ne "") {
+                               $define_args = substr($define_args, 1, length($define_args) - 2);
+                               $define_args =~ s/\s*//g;
+                               @def_args = split(",", $define_args);
+                       }
 
-                       $dstat =~ s/^.\s*\#\s*define\s+$Ident(?:\([^\)]*\))?\s*//;
                        $dstat =~ s/$;//g;
                        $dstat =~ s/\\\n.//g;
                        $dstat =~ s/^\s*//s;
@@ -4528,7 +4818,7 @@ sub process {
                        # Flatten any parentheses and braces
                        while ($dstat =~ s/\([^\(\)]*\)/1/ ||
                               $dstat =~ s/\{[^\{\}]*\}/1/ ||
-                              $dstat =~ s/\[[^\[\]]*\]/1/)
+                              $dstat =~ s/.\[[^\[\]]*\]/1/)
                        {
                        }
 
@@ -4538,6 +4828,9 @@ sub process {
                        {
                        }
 
+                       # Make asm volatile uses seem like a generic function
+                       $dstat =~ s/\b_*asm_*\s+_*volatile_*\b/asm_volatile/g;
+
                        my $exceptions = qr{
                                $Declare|
                                module_param_named|
@@ -4548,9 +4841,19 @@ sub process {
                                union|
                                struct|
                                \.$Ident\s*=\s*|
-                               ^\"|\"$
+                               ^\"|\"$|
+                               ^\[
                        }x;
                        #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";
+                       }
+
                        if ($dstat ne '' &&
                            $dstat !~ /^(?:$Ident|-?$Constant),$/ &&                    # 10, // foo(),
                            $dstat !~ /^(?:$Ident|-?$Constant);$/ &&                    # foo();
@@ -4566,21 +4869,56 @@ sub process {
                            $dstat !~ /^\(\{/ &&                                                # ({...
                            $ctx !~ /^.\s*#\s*define\s+TRACE_(?:SYSTEM|INCLUDE_FILE|INCLUDE_PATH)\b/)
                        {
-                               $ctx =~ s/\n*$//;
-                               my $herectx = $here . "\n";
-                               my $cnt = statement_rawlines($ctx);
-
-                               for (my $n = 0; $n < $cnt; $n++) {
-                                       $herectx .= raw_line($linenr, $n) . "\n";
-                               }
-
-                               if ($dstat =~ /;/) {
+                               if ($dstat =~ /^\s*if\b/) {
+                                       ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE",
+                                             "Macros starting with if should be enclosed by a do - while loop to avoid possible if/else logic defects\n" . "$herectx");
+                               } elsif ($dstat =~ /;/) {
                                        ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE",
                                              "Macros with multiple statements should be enclosed in a do - while loop\n" . "$herectx");
                                } else {
                                        ERROR("COMPLEX_MACRO",
                                              "Macros with complex values should be enclosed in parentheses\n" . "$herectx");
                                }
+
+                       }
+
+                       # Make $define_stmt single line, comment-free, etc
+                       my @stmt_array = split('\n', $define_stmt);
+                       my $first = 1;
+                       $define_stmt = "";
+                       foreach my $l (@stmt_array) {
+                               $l =~ s/\\$//;
+                               if ($first) {
+                                       $define_stmt = $l;
+                                       $first = 0;
+                               } elsif ($l =~ /^[\+ ]/) {
+                                       $define_stmt .= substr($l, 1);
+                               }
+                       }
+                       $define_stmt =~ s/$;//g;
+                       $define_stmt =~ s/\s+/ /g;
+                       $define_stmt = trim($define_stmt);
+
+# check if any macro arguments are reused (ignore '...' and 'type')
+                       foreach my $arg (@def_args) {
+                               next if ($arg =~ /\.\.\./);
+                               next if ($arg =~ /^type$/i);
+                               my $tmp = $define_stmt;
+                               $tmp =~ s/\b(typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g;
+                               $tmp =~ s/\#+\s*$arg\b//g;
+                               $tmp =~ s/\b$arg\s*\#\#//g;
+                               my $use_cnt = $tmp =~ s/\b$arg\b//g;
+                               if ($use_cnt > 1) {
+                                       CHK("MACRO_ARG_REUSE",
+                                           "Macro argument reuse '$arg' - possible side-effects?\n" . "$herectx");
+                                   }
+# check if any macro arguments may have other precedence issues
+                               if ($define_stmt =~ m/($Operators)?\s*\b$arg\b\s*($Operators)?/m &&
+                                   ((defined($1) && $1 ne ',') ||
+                                    (defined($2) && $2 ne ','))) {
+                                       CHK("MACRO_ARG_PRECEDENCE",
+                                           "Macro argument '$arg' may be better as '($arg)' to avoid precedence issues\n" . "$herectx");
+                               }
                        }
 
 # check for macros with flow control, but without ## concatenation
@@ -4788,6 +5126,12 @@ sub process {
                        }
                }
 
+# check for single line unbalanced braces
+               if ($sline =~ /^.\s*\}\s*else\s*$/ ||
+                   $sline =~ /^.\s*else\s*\{\s*$/) {
+                       CHK("BRACES", "Unbalanced braces around else statement\n" . $herecurr);
+               }
+
 # check for unnecessary blank lines around braces
                if (($line =~ /^.\s*}\s*$/ && $prevrawline =~ /^.\s*$/)) {
                        if (CHK("BRACES",
@@ -4808,7 +5152,7 @@ sub process {
                my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b};
                if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) {
                        WARN("VOLATILE",
-                            "Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr);
+                            "Use of volatile is usually wrong: see Documentation/process/volatile-considered-harmful.rst\n" . $herecurr);
                }
 
 # Check for user-visible strings broken across lines, which breaks the ability
@@ -4850,6 +5194,18 @@ sub process {
                             "break quoted strings at a space character\n" . $hereprev);
                }
 
+# check for an embedded function name in a string when the function is known
+# This does not work very well for -f --file checking as it depends on patch
+# context providing the function name or a single line form for in-file
+# function declarations
+               if ($line =~ /^\+.*$String/ &&
+                   defined($context_function) &&
+                   get_quoted_string($line, $rawline) =~ /\b$context_function\b/ &&
+                   length(get_quoted_string($line, $rawline)) != (length($context_function) + 2)) {
+                       WARN("EMBEDDED_FUNCTION_NAME",
+                            "Prefer using '\"%s...\", __func__' to using '$context_function', this function's name, in a string\n" . $herecurr);
+               }
+
 # check for spaces before a quoted newline
                if ($rawline =~ /^.*\".*\s\\n/) {
                        if (WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE",
@@ -4872,18 +5228,27 @@ sub process {
                             "Consecutive strings are generally better as a single string\n" . $herecurr);
                }
 
-# check for %L{u,d,i} and 0x%[udi] in strings
-               my $string;
+# check for non-standard and hex prefixed decimal printf formats
+               my $show_L = 1; #don't show the same defect twice
+               my $show_Z = 1;
                while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) {
-                       $string = substr($rawline, $-[1], $+[1] - $-[1]);
+                       my $string = substr($rawline, $-[1], $+[1] - $-[1]);
                        $string =~ s/%%/__/g;
-                       if ($string =~ /(?<!%)%[\*\d\.\$]*L[udi]/) {
+                       # check for %L
+                       if ($show_L && $string =~ /%[\*\d\.\$]*L([diouxX])/) {
                                WARN("PRINTF_L",
-                                    "\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr);
-                               last;
-                       }
-                       if ($string =~ /0x%[\*\d\.\$\Llzth]*[udi]/) {
-                               ERROR("PRINTF_0xDECIMAL",
+                                    "\%L$1 is non-standard C, use %ll$1\n" . $herecurr);
+                               $show_L = 0;
+                       }
+                       # check for %Z
+                       if ($show_Z && $string =~ /%[\*\d\.\$]*Z([diouxX])/) {
+                               WARN("PRINTF_Z",
+                                    "%Z$1 is non-standard C, use %z$1\n" . $herecurr);
+                               $show_Z = 0;
+                       }
+                       # check for 0x<decimal>
+                       if ($string =~ /0x%[\*\d\.\$\Llzth]*[diou]/) {
+                               ERROR("PRINTF_0XDECIMAL",
                                      "Prefixing 0x with decimal output is defective\n" . $herecurr);
                        }
                }
@@ -4962,6 +5327,12 @@ sub process {
                        }
                }
 
+# check for logging continuations
+               if ($line =~ /\bprintk\s*\(\s*KERN_CONT\b|\bpr_cont\s*\(/) {
+                       WARN("LOGGING_CONTINUATION",
+                            "Avoid logging continuation uses where feasible\n" . $herecurr);
+               }
+
 # check for mask then right shift without a parentheses
                if ($^V && $^V ge 5.10.0 &&
                    $line =~ /$LvalOrFunc\s*\&\s*($LvalOrFunc)\s*>>/ &&
@@ -5116,13 +5487,44 @@ sub process {
                        }
                }
 # check for memory barriers without a comment.
-               if ($line =~ /\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/) {
+
+               my $barriers = qr{
+                       mb|
+                       rmb|
+                       wmb|
+                       read_barrier_depends
+               }x;
+               my $barrier_stems = qr{
+                       mb__before_atomic|
+                       mb__after_atomic|
+                       store_release|
+                       load_acquire|
+                       store_mb|
+                       (?:$barriers)
+               }x;
+               my $all_barriers = qr{
+                       (?:$barriers)|
+                       smp_(?:$barrier_stems)|
+                       virt_(?:$barrier_stems)
+               }x;
+
+               if ($line =~ /\b(?:$all_barriers)\s*\(/) {
                        if (!ctx_has_comment($first_line, $linenr)) {
                                WARN("MEMORY_BARRIER",
                                     "memory barrier without comment\n" . $herecurr);
                        }
                }
 
+               my $underscore_smp_barriers = qr{__smp_(?:$barrier_stems)}x;
+
+               if ($realfile !~ m@^include/asm-generic/@ &&
+                   $realfile !~ m@/barrier\.h$@ &&
+                   $line =~ m/\b(?:$underscore_smp_barriers)\s*\(/ &&
+                   $line !~ m/^.\s*\#\s*define\s+(?:$underscore_smp_barriers)\s*\(/) {
+                       WARN("MEMORY_BARRIER",
+                            "__smp memory barriers shouldn't be used outside barrier.h and asm-generic\n" . $herecurr);
+               }
+
 # check for waitqueue_active without a comment.
                if ($line =~ /\bwaitqueue_active\s*\(/) {
                        if (!ctx_has_comment($first_line, $linenr)) {
@@ -5223,8 +5625,9 @@ sub process {
                              "Using weak declarations can have unintended link defects\n" . $herecurr);
                }
 
-# check for c99 types like uint8_t used outside of uapi/
+# check for c99 types like uint8_t used outside of uapi/ and tools/
                if ($realfile !~ m@\binclude/uapi/@ &&
+                   $realfile !~ m@\btools/@ &&
                    $line =~ /\b($Declare)\s*$Ident\s*[=;,\[]/) {
                        my $type = $1;
                        if ($type =~ /\b($typeC99Typedefs)\b/) {
@@ -5241,6 +5644,26 @@ sub process {
                        }
                }
 
+# check for cast of C90 native int or longer types constants
+               if ($line =~ /(\(\s*$C90_int_types\s*\)\s*)($Constant)\b/) {
+                       my $cast = $1;
+                       my $const = $2;
+                       if (WARN("TYPECAST_INT_CONSTANT",
+                                "Unnecessary typecast of c90 int constant\n" . $herecurr) &&
+                           $fix) {
+                               my $suffix = "";
+                               my $newconst = $const;
+                               $newconst =~ s/${Int_type}$//;
+                               $suffix .= 'U' if ($cast =~ /\bunsigned\b/);
+                               if ($cast =~ /\blong\s+long\b/) {
+                                       $suffix .= 'LL';
+                               } elsif ($cast =~ /\blong\b/) {
+                                       $suffix .= 'L';
+                               }
+                               $fixed[$fixlinenr] =~ s/\Q$cast\E$const\b/$newconst$suffix/;
+                       }
+               }
+
 # check for sizeof(&)
                if ($line =~ /\bsizeof\s*\(\s*\&/) {
                        WARN("SIZEOF_ADDRESS",
@@ -5275,6 +5698,32 @@ sub process {
                        }
                }
 
+               # check for vsprintf extension %p<foo> misuses
+               if ($^V && $^V ge 5.10.0 &&
+                   defined $stat &&
+                   $stat =~ /^\+(?![^\{]*\{\s*).*\b(\w+)\s*\(.*$String\s*,/s &&
+                   $1 !~ /^_*volatile_*$/) {
+                       my $bad_extension = "";
+                       my $lc = $stat =~ tr@\n@@;
+                       $lc = $lc + $linenr;
+                       for (my $count = $linenr; $count <= $lc; $count++) {
+                               my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0));
+                               $fmt =~ s/%%//g;
+                               if ($fmt =~ /(\%[\*\d\.]*p(?![\WFfSsBKRraEhMmIiUDdgVCbGN]).)/) {
+                                       $bad_extension = $1;
+                                       last;
+                               }
+                       }
+                       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);
+                               }
+                               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 &&
                    defined $stat &&
@@ -5294,46 +5743,46 @@ sub process {
                }
 
 # Check for memcpy(foo, bar, ETH_ALEN) that could be ether_addr_copy(foo, bar)
-               if ($^V && $^V ge 5.10.0 &&
-                   defined $stat &&
-                   $stat =~ /^\+(?:.*?)\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
-                       if (WARN("PREFER_ETHER_ADDR_COPY",
-                                "Prefer ether_addr_copy() over memcpy() if the Ethernet addresses are __aligned(2)\n" . "$here\n$stat\n") &&
-                           $fix) {
-                               $fixed[$fixlinenr] =~ s/\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/ether_addr_copy($2, $7)/;
-                       }
-               }
+#              if ($^V && $^V ge 5.10.0 &&
+#                  defined $stat &&
+#                  $stat =~ /^\+(?:.*?)\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
+#                      if (WARN("PREFER_ETHER_ADDR_COPY",
+#                               "Prefer ether_addr_copy() over memcpy() if the Ethernet addresses are __aligned(2)\n" . "$here\n$stat\n") &&
+#                          $fix) {
+#                              $fixed[$fixlinenr] =~ s/\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/ether_addr_copy($2, $7)/;
+#                      }
+#              }
 
 # Check for memcmp(foo, bar, ETH_ALEN) that could be ether_addr_equal*(foo, bar)
-               if ($^V && $^V ge 5.10.0 &&
-                   defined $stat &&
-                   $stat =~ /^\+(?:.*?)\bmemcmp\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
-                       WARN("PREFER_ETHER_ADDR_EQUAL",
-                            "Prefer ether_addr_equal() or ether_addr_equal_unaligned() over memcmp()\n" . "$here\n$stat\n")
-               }
+#              if ($^V && $^V ge 5.10.0 &&
+#                  defined $stat &&
+#                  $stat =~ /^\+(?:.*?)\bmemcmp\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
+#                      WARN("PREFER_ETHER_ADDR_EQUAL",
+#                           "Prefer ether_addr_equal() or ether_addr_equal_unaligned() over memcmp()\n" . "$here\n$stat\n")
+#              }
 
 # 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 &&
-                   defined $stat &&
-                   $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
-
-                       my $ms_val = $7;
-
-                       if ($ms_val =~ /^(?:0x|)0+$/i) {
-                               if (WARN("PREFER_ETH_ZERO_ADDR",
-                                        "Prefer eth_zero_addr over memset()\n" . "$here\n$stat\n") &&
-                                   $fix) {
-                                       $fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_zero_addr($2)/;
-                               }
-                       } elsif ($ms_val =~ /^(?:0xff|255)$/i) {
-                               if (WARN("PREFER_ETH_BROADCAST_ADDR",
-                                        "Prefer eth_broadcast_addr() over memset()\n" . "$here\n$stat\n") &&
-                                   $fix) {
-                                       $fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_broadcast_addr($2)/;
-                               }
-                       }
-               }
+#              if ($^V && $^V ge 5.10.0 &&
+#                  defined $stat &&
+#                  $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
+#
+#                      my $ms_val = $7;
+#
+#                      if ($ms_val =~ /^(?:0x|)0+$/i) {
+#                              if (WARN("PREFER_ETH_ZERO_ADDR",
+#                                       "Prefer eth_zero_addr over memset()\n" . "$here\n$stat\n") &&
+#                                  $fix) {
+#                                      $fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_zero_addr($2)/;
+#                              }
+#                      } elsif ($ms_val =~ /^(?:0xff|255)$/i) {
+#                              if (WARN("PREFER_ETH_BROADCAST_ADDR",
+#                                       "Prefer eth_broadcast_addr() over memset()\n" . "$here\n$stat\n") &&
+#                                  $fix) {
+#                                      $fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_broadcast_addr($2)/;
+#                              }
+#                      }
+#              }
 
 # typecasts on min/max could be min_t/max_t
                if ($^V && $^V ge 5.10.0 &&
@@ -5453,13 +5902,26 @@ sub process {
                             "externs should be avoided in .c files\n" .  $herecurr);
                }
 
+               if ($realfile =~ /\.[ch]$/ && defined $stat &&
+                   $stat =~ /^.\s*(?:extern\s+)?$Type\s*$Ident\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) {
+                               my $arg = trim($1);
+                               if ($arg =~ /^$Type$/ && $arg !~ /enum\s+$Ident$/) {
+                                       WARN("FUNCTION_ARGUMENTS",
+                                            "function definition argument '$arg' should also have an identifier name\n" . $herecurr);
+                               }
+                       }
+               }
+
 # checks for new __setup's
                if ($rawline =~ /\b__setup\("([^"]*)"/) {
                        my $name = $1;
 
                        if (!grep(/$name/, @setup_docs)) {
                                CHK("UNDOCUMENTED_SETUP",
-                                   "__setup appears un-documented -- check Documentation/kernel-parameters.txt\n" . $herecurr);
+                                   "__setup appears un-documented -- check Documentation/admin-guide/kernel-parameters.rst\n" . $herecurr);
                        }
                }
 
@@ -5479,7 +5941,8 @@ sub process {
 
 # check for k[mz]alloc with multiplies that could be kmalloc_array/kcalloc
                if ($^V && $^V ge 5.10.0 &&
-                   $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) {
+                   defined $stat &&
+                   $stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) {
                        my $oldfunc = $3;
                        my $a1 = $4;
                        my $a2 = $10;
@@ -5493,11 +5956,17 @@ 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";
+                               }
                                if (WARN("ALLOC_WITH_MULTIPLY",
-                                        "Prefer $newfunc over $oldfunc with multiply\n" . $herecurr) &&
+                                        "Prefer $newfunc over $oldfunc with multiply\n" . $herectx) &&
+                                   $cnt == 1 &&
                                    $fix) {
                                        $fixed[$fixlinenr] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/$1 . ' = ' . "$newfunc(" . trim($r1) . ', ' . trim($r2)/e;
-
                                }
                        }
                }
@@ -5524,8 +5993,9 @@ sub process {
                        }
                }
 
-# check for #defines like: 1 << <digit> that could be BIT(digit)
-               if ($line =~ /#\s*define\s+\w+\s+\(?\s*1\s*([ulUL]*)\s*\<\<\s*(?:\d+|$Ident)\s*\)?/) {
+# check for #defines like: 1 << <digit> that could be BIT(digit), it is not exported to uapi
+               if ($realfile !~ m@^include/uapi/@ &&
+                   $line =~ /#\s*define\s+\w+\s+\(?\s*1\s*([ulUL]*)\s*\<\<\s*(?:\d+|$Ident)\s*\)?/) {
                        my $ull = "";
                        $ull = "_ULL" if (defined($1) && $1 =~ /ll/i);
                        if (CHK("BIT_MACRO",
@@ -5535,6 +6005,16 @@ sub process {
                        }
                }
 
+# check for #if defined CONFIG_<FOO> || defined CONFIG_<FOO>_MODULE
+               if ($line =~ /^\+\s*#\s*if\s+defined(?:\s*\(?\s*|\s+)(CONFIG_[A-Z_]+)\s*\)?\s*\|\|\s*defined(?:\s*\(?\s*|\s+)\1_MODULE\s*\)?\s*$/) {
+                       my $config = $1;
+                       if (WARN("PREFER_IS_ENABLED",
+                                "Prefer IS_ENABLED(<FOO>) to CONFIG_<FOO> || CONFIG_<FOO>_MODULE\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$fixlinenr] = "\+#if IS_ENABLED($config)";
+                       }
+               }
+
 # check for case / default statements not preceded by break/fallthrough/switch
                if ($line =~ /^.\s*(?:case\s+(?:$Ident|$Constant)\s*|default):/) {
                        my $has_break = 0;
@@ -5556,7 +6036,7 @@ sub process {
                        }
                        if (!$has_break && $has_statement) {
                                WARN("MISSING_BREAK",
-                                    "Possible switch case/default not preceeded by break or fallthrough comment\n" . $herecurr);
+                                    "Possible switch case/default not preceded by break or fallthrough comment\n" . $herecurr);
                        }
                }
 
@@ -5641,51 +6121,11 @@ sub process {
                }
 
 # check for various structs that are normally const (ops, kgdb, device_tree)
-               my $const_structs = qr{
-                               acpi_dock_ops|
-                               address_space_operations|
-                               backlight_ops|
-                               block_device_operations|
-                               dentry_operations|
-                               dev_pm_ops|
-                               dma_map_ops|
-                               extent_io_ops|
-                               file_lock_operations|
-                               file_operations|
-                               hv_ops|
-                               ide_dma_ops|
-                               intel_dvo_dev_ops|
-                               item_operations|
-                               iwl_ops|
-                               kgdb_arch|
-                               kgdb_io|
-                               kset_uevent_ops|
-                               lock_manager_operations|
-                               microcode_ops|
-                               mtrr_ops|
-                               neigh_ops|
-                               nlmsvc_binding|
-                               of_device_id|
-                               pci_raw_ops|
-                               pipe_buf_operations|
-                               platform_hibernation_ops|
-                               platform_suspend_ops|
-                               proto_ops|
-                               rpc_pipe_ops|
-                               seq_operations|
-                               snd_ac97_build_ops|
-                               soc_pcmcia_socket_ops|
-                               stacktrace_ops|
-                               sysfs_ops|
-                               tty_operations|
-                               uart_ops|
-                               usb_mon_operations|
-                               wd_ops}x;
+# and avoid what seem like struct definitions 'struct foo {'
                if ($line !~ /\bconst\b/ &&
-                   $line =~ /\bstruct\s+($const_structs)\b/) {
+                   $line =~ /\bstruct\s+($const_structs)\b(?!\s*\{)/) {
                        WARN("CONST_STRUCT",
-                            "struct $1 should normally be const\n" .
-                               $herecurr);
+                            "struct $1 should normally be const\n" . $herecurr);
                }
 
 # use of NR_CPUS is usually wrong
@@ -5725,6 +6165,34 @@ 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",
+                             "recursive locking is bad, do not use this ever.\n" . $herecurr);
+               }
+
 # check for lockdep_set_novalidate_class
                if ($line =~ /^.\s*lockdep_set_novalidate_class\s*\(/ ||
                    $line =~ /__lockdep_no_validate__\s*\)/ ) {
@@ -5745,34 +6213,69 @@ sub process {
 # 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 &&
+                   defined $stat &&
                    $line =~ /$mode_perms_search/) {
                        foreach my $entry (@mode_permission_funcs) {
                                my $func = $entry->[0];
                                my $arg_pos = $entry->[1];
 
+                               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 $skip_args = "";
                                if ($arg_pos > 1) {
                                        $arg_pos--;
                                        $skip_args = "(?:\\s*$FuncArg\\s*,\\s*){$arg_pos,$arg_pos}";
                                }
-                               my $test = "\\b$func\\s*\\(${skip_args}([\\d]+)\\s*[,\\)]";
-                               if ($line =~ /$test/) {
+                               my $test = "\\b$func\\s*\\(${skip_args}($FuncArg(?:\\|\\s*$FuncArg)*)\\s*[,\\)]";
+                               if ($stat =~ /$test/) {
                                        my $val = $1;
                                        $val = $6 if ($skip_args ne "");
-
-                                       if ($val !~ /^0$/ &&
-                                           (($val =~ /^$Int$/ && $val !~ /^$Octal$/) ||
-                                            length($val) ne 4)) {
+                                       if (($val =~ /^$Int$/ && $val !~ /^$Octal$/) ||
+                                           ($val =~ /^$Octal$/ && length($val) ne 4)) {
                                                ERROR("NON_OCTAL_PERMISSIONS",
-                                                     "Use 4 digit octal (0777) not decimal permissions\n" . $herecurr);
-                                       } elsif ($val =~ /^$Octal$/ && (oct($val) & 02)) {
+                                                     "Use 4 digit octal (0777) not decimal permissions\n" . "$here\n" . $stat_real);
+                                       }
+                                       if ($val =~ /^$Octal$/ && (oct($val) & 02)) {
                                                ERROR("EXPORTED_WORLD_WRITABLE",
-                                                     "Exporting writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr);
+                                                     "Exporting writable files is usually an error. Consider more restrictive permissions.\n" . "$here\n" . $stat_real);
                                        }
                                }
                        }
                }
 
+# 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);
+                       if (WARN("SYMBOLIC_PERMS",
+                                "Symbolic permissions '$oval' are not preferred. Consider using octal permissions '$octal'.\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$fixlinenr] =~ s/$val/$octal/;
+                       }
+               }
+
 # validate content of MODULE_LICENSE against list from include/linux/module.h
                if ($line =~ /\bMODULE_LICENSE\s*\(\s*($String)\s*\)/) {
                        my $extracted_string = get_quoted_string($line, $rawline);
@@ -5814,7 +6317,7 @@ sub process {
                ERROR("NOT_UNIFIED_DIFF",
                      "Does not appear to be a unified-diff format patch\n");
        }
-       if ($is_patch && $filename ne '-' && $chk_signoff && $signoff == 0) {
+       if ($is_patch && $has_commit_log && $chk_signoff && $signoff == 0) {
                ERROR("MISSING_SIGN_OFF",
                      "Missing Signed-off-by: line(s)\n");
        }
@@ -5828,6 +6331,14 @@ sub process {
        }
 
        if ($quiet == 0) {
+               # If there were any defects found and not already fixing them
+               if (!$clean and !$fix) {
+                       print << "EOM"
+
+NOTE: For some of the reported defects, checkpatch may be able to
+      mechanically convert to the typical style using --fix or --fix-inplace.
+EOM
+               }
                # If there were whitespace errors which cleanpatch can fix
                # then suggest that.
                if ($rpt_cleaners) {