Bugs and fixes in the kernel history
Tagged fixes
In current kernel practice, a developer who fixes a bug is expected to include a Fixes tag in the patch description identifying the commit that introduced that bug. This is a relatively recent practice; while various forms of Fixes tags had appeared in commits for some time, the first patch using the current form with the hash of the offending commit appears to be this revert from Rafael Wysocki for 3.12 in October 2013. In that release, only two commits identified buggy commits from previous releases, but the use of this tag grew quickly in subsequent development cycles. The 6.0 kernel release included 2,784 commits with Fixes tags, 2,112 of which identified commits from previous releases as the source of the bug being fixed (the remaining commits fixed bugs that had been introduced in 6.0 and thus never appeared in a released kernel).
Thus, in theory, one can simply count Fixes tags over a development cycle to see how many bugs from previous releases were fixed. Then, looking at subsequent releases, the Fixes tags can be used to see how many bugs were introduced in that cycle and fixed in later cycles. If the number of bugs fixed in a development cycle regularly exceeds the number of bugs introduced in that cycle, then chances are good that the kernel is getting better over time. The idea is simple, but runs into some practical difficulties that will be explored later on. We can start with a plot showing how the above analysis comes out:
(This data can also be viewed in tabular form on this page).
In the above plot, the thicker lines are counts of Fixes tags; so the brown "bugs introduced" line is the number of times that a commit in a given release was identified by a Fixes tag in subsequent releases, while the green "bugs fixed" line shows the number of Fixes tags in a given release identifying buggy commits in previous releases. The thinner lines are instead counting commits: "buggy commits introduced" is the number of commits in a given release that were later fixed, and "commits fixed" is the number of commits from previous releases that were fixed in a given release.
The two sets of numbers differ for a simple reason: some commits are sufficiently buggy that they need to be fixed more than once — a topic we'll return to shortly. There is an interesting difference here, though: in any given development cycle, the number of bugs fixed tracks closely with the number of commits fixed, but there is a big difference between the number of bugs introduced and the number of buggy commits introduced. What we can conclude from this difference is that commits that introduce a lot of bugs require multiple development cycles for all of those bugs to be fixed. It is rare to see a lot of fixes to the same commit in any one development cycle.
Can this plot answer the question posed at the beginning of this article, though? A naive reading shows that the lines cross and that, thus, number of bugs fixed exceeds the number of bugs introduced as of the 5.1 release. But that result must clearly be taken with a fair amount of salt. As has been seen in other recent examinations of Fixes tags, bugs lurk in the kernel for a long time. Kernel developers are still finding and fixing bugs introduced early in the 2.6 era — and before. So the "bugs introduced" numbers for recent kernels are clearly too low, as can be seen by the fact that those lines head toward zero for the most recent releases.
The number of bugs introduced does appear, though, to level out in the range of 1,200 to 1,400 per release; this can be seen in the older releases, where the numbers are unlikely to change much at this point. That trend seems to continue through about 5.8 or so, after which the curve drops down and clearly does not reflect long-term reality. Should this pattern hold — something only time will tell — then the point where the curves cross may move, but it seems likely to remain in the early 5.x era. If that is truly the case then, in recent times at least, the kernel community may well be fixing more bugs than it is introducing.
What might have caused the situation to change? Your editor does not know but can wave his hands as well as anybody else. One possibility is improved development tools and, especially, the increased use of fuzz testing to turn up old bugs and prevent new ones. The slow but steady growth in the kernel's (still inadequate) testing infrastructure will have helped. Increased insistence on patch review may have helped to keep the number of bugs introduced roughly constant even as the volume of code going into the kernel has increased. Or perhaps none of the above applies.
It is also almost certainly true that developers have become more disciplined about adding Fixes tags, causing more bug fixes to actually be counted as such while not actually reflecting a change in the rate at which fixes are happening. In general, Fixes tags may be the best proxy we have for actual bug counts, but they are still an inaccurate metric; it depends on developers to carefully add them and to correctly identify the commits that introduce bugs.
The buggiest commits
One thing those tags might do reliably, though, is to identify the buggiest commits in the kernel's history. Remember that some commits require more than one fix over time; some of them require quite a few more than one. Here is a table of the most-fixed commits during the Git era:
Commit Fixes Description 1da177e4c3f4 355 Linux-2.6.12-rc2 e126ba97dba9 70 mlx5: Add driver for Mellanox Connect-IB adapters 8700e3e7c485 65 Soft RoCE driver 46a3df9f9718 54 net: hns3: Add HNS3 Acceleration Engine & Compatibility Layer Support 9d71dd0c7009 42 can: add support of SAE J1939 protocol 76ad4f0ee747 38 net: hns3: Add support of HNS3 Ethernet Driver for hip08 SoC 604326b41a6f 38 bpf, sockmap: convert to generic sk_msg interface 1738cd3ed342 38 net: ena: Add a driver for Amazon Elastic Network Adapters (ENA) e1eaea46bb40 35 tty: n_gsm line discipline e7096c131e51 34 net: WireGuard secure network tunnel 1c1008c793fa 33 net: bcmgenet: add main driver file d5c65159f289 29 ath11k: driver for Qualcomm IEEE 802.11ax devices c0c050c58d84 27 bnxt_en: New Broadcom ethernet driver. c09440f7dcb3 27 macsec: introduce IEEE 802.1AE driver 7724105686e7 26 IB/hfi1: add driver files d2ead1f360e8 25 net/mlx5e: Add kTLS TX HW offload support 7733f6c32e36 25 usb: cdns3: Add Cadence USB3 DRD Driver 726b85487067 24 qla2xxx: Add framework for async fabric discovery 1e51764a3c2a 24 UBIFS: add new flash file system a49d25364dfb 24 staging/atomisp: Add support for the Intel IPU v2 96c8395e2166 24 spi: Revert modalias changes 3c4d7559159b 23 tls: kernel TLS support d7157ff49a5b 23 mtd: rawnand: Use the ECC framework user input parsing bits 6a98d71daea1 22 RDMA/rtrs: client: main functionality 3f518509dedc 22 ethernet: Add new driver for Marvell Armada 375 network unit ca6fb0651883 21 tcp: attach SYNACK messages to request sockets instead of listener ad67b74d2469 21 printk: hash addresses printed with %p c29f74e0df7a 20 netfilter: nf_flow_table: hardware offload support d2ddc776a458 20 afs: Overhaul volume and server record caching and fileserver rotation 1a86b377aa21 20 vdpa/mlx5: Add VDPA driver for supported mlx5 devices
One might wonder about what went wrong with Linux-2.6.12-rc2, which has been fixed (at last count) 355 times. That is, of course, the initial commit that started the Git era, so fixes identifying that commit are for bugs that were introduced prior to April 2005. Even in 2022, bugs of that vintage are still being found and fixed.
After that, the conclusion to be drawn is not that surprising: the commits that need a lot of fixes tend to be the large ones that add a significant new subsystem. A lot of new code will inevitably bring a fair number of new bugs with it, and those bugs will need to be discovered and fixed over time. One interesting exception might be ca6fb0651883 ("tcp: attach SYNACK messages to request sockets instead of listener") which inserted 47 lines in 2015 and has been fixed 21 times since, most recently in February for 5.17. Also noteworthy is 96c8395e2166 ("spi: Revert modalias changes"), which deleted six lines of code and has required 24 fixes thereafter. Beyond those, though, the commits needing a large number of fixes have been large in their own right.
Perhaps more interesting is the fact that, of the 30 most-fixed commits shown above, 22 are related to networking (including InfiniBand). The networking subsystem is a large part of the kernel, but it is still a small piece of the whole and not the only subsystem that merges large patches. It's not clear why networking-related patches, in particular, would be more likely to need many fixes.
Bugs are a fact of life in software development, unfortunately, and we are
unlikely to be free of them anytime soon. If an optimistic reading of the
data above reflects reality, though, then it is possible that the
kernel-development community may have reached a point where it is fixing
more bugs than it
introduces. LWN will surely revisit this topic in the future to see how
the situation evolves.
Index entries for this article | |
---|---|
Kernel | Development model/Kernel quality |
Posted Dec 8, 2022 18:01 UTC (Thu)
by jgg (subscriber, #55211)
[Link] (3 responses)
What I find surprising is I don't see any FS in this list, are they not using fixes lines in the same way?
Posted Dec 8, 2022 20:12 UTC (Thu)
by smurf (subscriber, #17840)
[Link]
Posted Dec 8, 2022 20:15 UTC (Thu)
by mathstuf (subscriber, #69389)
[Link]
> UBIFS: add new flash file system
It could be, however, that FS developers have smaller commits that are unlikely to individually need fixed a few dozen times? This example sounds like a "large commit" based on the commit summary at least…
Posted Dec 13, 2022 16:06 UTC (Tue)
by kdave (subscriber, #44472)
[Link]
8 Fixes: afba2bc036b ("btrfs: zoned: implement active zone tracking")
It's a mix of new features or functionality changes but with unforseen consequences, the patches are not that big on average (except 79787eaab46 which is merge of about 60 few-liner patches). In the sample there are about 600 Fixes tags, median is 1, average 1.29. With good change granularity at most one fixup is IMHO a good result, bug hunting usually improves understanding and there remaining bugs are fixed at once. The exceptions in the list are from specific use case or not widely tested (zoned mode) or hard to hit bugs, d2311e69857 took a long time to track down.
Posted Dec 8, 2022 22:04 UTC (Thu)
by plugwash (subscriber, #29694)
[Link] (1 responses)
Posted Dec 9, 2022 0:56 UTC (Fri)
by shemminger (subscriber, #5739)
[Link]
In preparing for battle I have always found that plans are useless but planning is indispensable.
Posted Dec 9, 2022 8:29 UTC (Fri)
by error27 (subscriber, #8346)
[Link]
The networking subsystem started enforcing a policy that Fixes had to have tags earlier than other subsystems so perhaps that's why they have more.
Posted Dec 9, 2022 13:58 UTC (Fri)
by andy_shev (subscriber, #75870)
[Link] (1 responses)
Posted Dec 9, 2022 14:18 UTC (Fri)
by pbonzini (subscriber, #60935)
[Link]
Posted Dec 11, 2022 19:42 UTC (Sun)
by sgruszka (guest, #71482)
[Link] (1 responses)
Would be interesting to see stats from bugzilla.kernel.org , how many bugs are open there for particular kernel version, how many get closed , how much time on average take to close the bug, etc. At least for subsystems that use bugzilla for bug tracking.
Posted Dec 13, 2022 0:19 UTC (Tue)
by shemminger (subscriber, #5739)
[Link]
Posted Dec 30, 2022 18:08 UTC (Fri)
by moorray (subscriber, #54145)
[Link]
I wonder if it's a matter of maintainer policy? Networking required Fixes tags on all fixes for years at this point, while historically discouraging ccing stable.
Posted Feb 22, 2023 18:37 UTC (Wed)
by nix (subscriber, #2304)
[Link]
(As someone busy doing that sort of thing right now, I'm avoiding this problem by putting in the massive multi-subsystem series before I introduce the commits that rely on it. This is usually a better ordering, but not if that 'relying commit' is fixing a live bug that likely bites everyone and the multi-subsystem fixes that follow are fixing cases that bite fewer people.)
Bugs and fixes in the kernel history
Bugs and fixes in the kernel history
Bugs and fixes in the kernel history
Bugs and fixes in the kernel history
7 Fixes: edf064e7c6f ("btrfs: nowait aio support")
6 Fixes: d2311e69857 ("btrfs: relocation: Delay reloc tree deletion after merge_reloc_roots")
6 Fixes: 7b508037d4c ("btrfs: defrag: use defrag_one_cluster() to implement btrfs_defrag_file()")
6 Fixes: 79787eaab46 ("btrfs: replace many BUG_ONs with proper error handling")
5 Fixes: 18bb8bbf13c ("btrfs: zoned: automatically reclaim zones")
5 Fixes: 16e7549f045 ("Btrfs: incompatible format change to remove hole extents")
New features vs regressions.
New features vs regressions.
Despite the efforts of developers, bugs start showing up as soon as the new driver gets exposure.
- Dwight D. Eisenhower
Bugs and fixes in the kernel history
Bugs and fixes in the kernel history
Bugs and fixes in the kernel history
Bugs and fixes in the kernel history
Bugs and fixes in the kernel history
Bugs and fixes in the kernel history
(... catching up...)
Bugs and fixes in the kernel history
One interesting exception
Both these exceptions are making a change and then doing the same mechanical transformation to a lot of different places as fallout, each as a separate commit -- but they're all conceptually the same thing and are likely separate commits just because they touch different subsystems and thus go in via different routes. So really these two exceptions required either a single fix, or none (because the original commit wasn't actually buggy as such: it just needed changes to other subsystems as well, and used Fixes: to denote that the original commit wouldn't work properly until these other commits were in too).