LinuxカーネルHack: scripts/checkpatch.plでパッチスタイルの適合性を判定する

昨日からLKMLの購読をはじめた。がんがんメールが飛んでくる。

つい最近届いた「[PATCH 01/10] Fs: ext4: acl.c: fixed indent issue」というメールがあって、内容を見ると、単にインデントを修正しただけという内容。

Found and corrected indent issue using checkpatch.pl

checkpatch.plってなんだろう?と思って、findをかけてみる。

% find . | grep checkpatch.pl
./scripts/checkpatch.pl

checkpatch.plの変更履歴を追ってみる。checkpatch.plは要はパッチのコードチェッカーと。コーディングスタイルから外れているものや、関数等の利用が適切でないなどを指摘してくれる。2007年6月から導入された仕組みの模様。以下はcheckpatch.plが追加された時のコミット。

% git log -p --stat --color --full-diff scripts/checkpatch.pl | less -NMR
[...]
  15948 commit 0a920b5b666d0be8141bd1ce620fffa7de96b81b
  15949 Author: Andy Whitcroft <apw@shadowen.org>
  15950 Date:   Fri Jun 1 00:46:48 2007 -0700
  15951
  15952     add a trivial patch style checker
  15953
  15954     We are seeing increasing levels of minor patch style violations in submissions
  15955     to the mailing lists as well as making it into the tree.  These detract from
  15956     the quality of the submission and cause unnessary work for reviewers.
  15957
  15958     As a first step package up the current state of the patch style checker and
  15959     include it in the kernel tree.  Add instructions suggesting running it on
  15960     submissions.  This adds version v0.01 of the checkpatch.pl script.
  15961
  15962     Signed-off-by: Andy Whitcroft <apw@shadowen.org>
  15963     Signed-off-by: Joel Schopp <jschopp@austin.ibm.com>
  15964     Cc: Randy Dunlap <rdunlap@xenotime.net>
  15965     Cc: Dave Jones <davej@codemonkey.org.uk>
  15966     Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
  15967     Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  15968 ---
  15969  Documentation/SubmitChecklist              |    6 +
  15970  Documentation/SubmittingPatches            |   39 ++-
  15971  Documentation/feature-removal-schedule.txt |    1 +
  15972  MAINTAINERS                                |   16 +-
  15973  scripts/checkpatch.pl                      |  595 ++++++++++++++++++++++++++++
  15974  5 files changed, 644 insertions(+), 13 deletions(-)
[...]

パッチを投稿する前に、コーディングスタイルを整えて、最低限checkpatch.plを通すようにと、パッチ投稿手順に明記されている。

% less Documentation/SubmittingPatches
[...]
4) Style check your changes.

Check your patch for basic style violations, details of which can be
found in Documentation/CodingStyle.  Failure to do so simply wastes
the reviewers time and will get your patch rejected, probably
without even being read.

At a minimum you should check your patches with the patch style
checker prior to submission (scripts/checkpatch.pl).  You should
be able to justify all violations that remain in your patch.
[...]

最近の変更履歴を読んでみる。どうやら結構細かいチェックまでやってくれるっぽい。msleep()の引数の中までチェックしてくれると。

% git log -p --stat --color --full-diff scripts/checkpatch.pl | less -NMR
[...]
     55 commit 09ef87255da0e005dd0ab39ca25714208cf29cb3
     56 Author: Patrick Pannuto <ppannuto@codeaurora.org>
     57 Date:   Mon Aug 9 17:21:02 2010 -0700
     58
     59     checkpatch: warn about unexpectedly long msleep's
     60
     61     As explained in Documentation/timers/timers-howto.txt, msleep's of < 20ms
     62     may sleep for as long as 20ms.  Caller's of msleep(1) or msleep(2), etc
     63     are likely not to expect this quirky behavior - warn them.
     64
     65     Signed-off-by: Patrick Pannuto <ppannuto@codeaurora.org>
     66     Cc: Thomas Gleixner <tglx@linutronix.de>
     67     Cc: Ingo Molnar <mingo@elte.hu>
     68     Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
     69     Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
     70 ---
     71  scripts/checkpatch.pl |    7 +++++++
     72  1 files changed, 7 insertions(+), 0 deletions(-)
     73
     74 diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
     75 index 8b69af8..dd11bbe 100755
     76 --- a/scripts/checkpatch.pl
     77 +++ b/scripts/checkpatch.pl
     78 @@ -2592,6 +2592,13 @@ sub process {
     79                         }
     80                 }
     81
     82 +# warn about unexpectedly long msleep's
     83 +               if ($line =~ /\bmsleep\s*\((\d+)\);/) {
     84 +                       if ($1 < 20) {
     85 +                               WARN("msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt\n" .      85 $line);
     86 +                       }
     87 +               }
     88 +
[...]

ちなみに、Documentation/feature-removal-schedule.txtには、将来廃止予定のファイルや関数がリストアップされていて、checkpatch.plはそれらを使用したら、警告が出る仕組みにもなってる。今の所、feature-removal-schedule.txtには「Check:」からはじまる行は数箇所なので、それほど恩恵は無いかもしれないけど。

% cat scripts/checkpatch.pl
[...]
my @dep_includes = ();
my @dep_functions = ();
my $removal = "Documentation/feature-removal-schedule.txt";
if ($tree && -f "$root/$removal") {
        open(my $REMOVE, '<', "$root/$removal") ||
                                die "$P: $removal: open failed - $!\n";
        while (<$REMOVE>) {
                if (/^Check:\s+(.*\S)/) {
                        for my $entry (split(/[, ]+/, $1)) {
                                if ($entry =~ m@include/(.*)@) {
                                        push(@dep_includes, $1);

                                } elsif ($entry !~ m@/@) {
                                        push(@dep_functions, $entry);
                                }
                        }
                }
        }
        close($REMOVE);
}
[...]
# don't include deprecated include files (uses RAW line)
                for my $inc (@dep_includes) {
                        if ($rawline =~ m@^.\s*\#\s*include\s*\<$inc>@) {
                                ERROR("Don't use <$inc>: see Documentation/feature-removal-schedule.txt\n" . $herecurr);
                        }
                }

# don't use deprecated functions
                for my $func (@dep_functions) {
                        if ($line =~ /\b$func\b/) {
                                ERROR("Don't use $func(): see Documentation/feature-removal-schedule.txt\n" . $herecurr);
                        }
                }

どんな感じでチェックされるのか試してみる。以下のような変更をしてみた。

% git diff
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index a0d847c..e6d5e17 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -93,6 +93,7 @@
 #include <net/checksum.h>
 #include <net/xfrm.h>
 #include <net/inet_common.h>
+#include <linux/videodev.h>

 /*
  *     Build xmit assembly blocks
@@ -221,6 +222,13 @@ static inline struct sock *icmp_xmit_lock(struct net *net)
                local_bh_enable();
                return NULL;
        }
+       // C99 comment
+       printk("No facility");
+       foo("Looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong message");
+       printk(KERN_WARN "Looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong message");
+        indented_with_spaces_not_tabs();
+       msleep(10);
+       kernel_thread();
        return sk;
 }

おー。なるほど、こんな感じでチェックしてくれるのか。checkpatch.plのように、解決したいドメインにあわせて、自前でコードチェックツールを作るというアイデアは、実際の仕事でも使えるアイデアだな。

% git diff > /tmp/diff && perl scripts/checkpatch.pl /tmp/diff
ERROR: Don't use <linux/videodev.h>: see Documentation/feature-removal-schedule.txt
#9: FILE: net/ipv4/icmp.c:96:
+#include <linux/videodev.h>

ERROR: do not use C99 // comments
#17: FILE: net/ipv4/icmp.c:225:
+       // C99 comment

WARNING: printk() should include KERN_ facility level
#18: FILE: net/ipv4/icmp.c:226:
+       printk("No facility");

WARNING: line over 80 characters
#19: FILE: net/ipv4/icmp.c:227:
+       foo("Looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong message");

ERROR: code indent should use tabs where possible
#21: FILE: net/ipv4/icmp.c:229:
+        indented_with_spaces_not_tabs();$

WARNING: please, no space for starting a line,
                                excluding comments
#21: FILE: net/ipv4/icmp.c:229:
+        indented_with_spaces_not_tabs();$

WARNING: msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt
+       msleep(10);
ERROR: Don't use kernel_thread(): see Documentation/feature-removal-schedule.txt
#23: FILE: net/ipv4/icmp.c:231:
+       kernel_thread();

ERROR: Missing Signed-off-by: line(s)

total: 5 errors, 4 warnings, 20 lines checked

/tmp/diff has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.